TypeScript

阅读数:111 评论数:0

跳转到新版页面

分类

html/css/js

正文

一、概述

TypeScript是微软开发的javascript加强版,就有带了type的javascript,主要用于解决:弱类型和没有命名空间,导致很难模块化

TS允许你以接口的形式定义复杂的类型,当你要在应用程序中使用复杂的对象或数组时,会进行严格的静态类型审查,增加健壮性。

:<TypeAnnotation>

TypeScript的基本类型语法是在变量之后使用冒号进行类型标识,这种语法也揭示了TypeScript的类型声明实际上是可选的。

umi中内置了TypeScript的loader,可以直接创建.tsx或者.tx文件来写TypeScrpit代码。

1、首先安装依赖包

cnpm install tslint tslint-config-prettier tslint-react @types/react @types/react-dom --save

2、然后需要新建tsconfig.json和tslint.json文件

tsconfig.json来声明这是一个TypeScrpit项目,并进行配置。

tslint类似eslint是一个代码风格检查器。

二、tsconfig.json

你可以通过compilerOptions来定制你的编译选项:

{
  "compilerOptions": {
 
    /* 基本选项 */
    "target": "es5",                       // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'
    "module": "commonjs",                  // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
    "lib": [],                             // 指定要包含在编译中的库文件
    "allowJs": true,                       // 允许编译 javascript 文件
    "checkJs": true,                       // 报告 javascript 文件中的错误
    "jsx": "preserve",                     // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
    "declaration": true,                   // 生成相应的 '.d.ts' 文件
    "sourceMap": true,                     // 生成相应的 '.map' 文件
    "outFile": "./",                       // 将输出文件合并为一个文件
    "outDir": "./",                        // 指定输出目录
    "rootDir": "./",                       // 用来控制输出目录结构 --outDir.
    "removeComments": true,                // 删除编译后的所有的注释
    "noEmit": true,                        // 不生成输出文件
    "importHelpers": true,                 // 从 tslib 导入辅助工具函数
    "isolatedModules": true,               // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似).
 
    /* 严格的类型检查选项 */
    "strict": true,                        // 启用所有严格类型检查选项
    "noImplicitAny": true,                 // 在表达式和声明上有隐含的 any类型时报错
    "strictNullChecks": true,              // 启用严格的 null 检查
    "noImplicitThis": true,                // 当 this 表达式值为 any 类型的时候,生成一个错误
    "alwaysStrict": true,                  // 以严格模式检查每个模块,并在每个文件里加入 'use strict'
 
    /* 额外的检查 */
    "noUnusedLocals": true,                // 有未使用的变量时,抛出错误
    "noUnusedParameters": true,            // 有未使用的参数时,抛出错误
    "noImplicitReturns": true,             // 并不是所有函数里的代码都有返回值时,抛出错误
    "noFallthroughCasesInSwitch": true,    // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)
 
    /* 模块解析选项 */
    "moduleResolution": "node",            // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)
    "baseUrl": "./",                       // 用于解析非相对模块名称的基目录
    "paths": {},                           // 模块名到基于 baseUrl 的路径映射的列表
    "rootDirs": [],                        // 根文件夹列表,其组合内容表示项目运行时的结构内容
    "typeRoots": [],                       // 包含类型声明的文件列表
    "types": [],                           // 需要包含的类型声明文件名列表
    "allowSyntheticDefaultImports": true,  // 允许从没有设置默认导出的模块中默认导入。
 
    /* Source Map Options */
    "sourceRoot": "./",                    // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
    "mapRoot": "./",                       // 指定调试器应该找到映射文件而不是生成文件的位置
    "inlineSourceMap": true,               // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
    "inlineSources": true,                 // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性
 
    /* 其他选项 */
    "experimentalDecorators": true,        // 启用装饰器
    "emitDecoratorMetadata": true          // 为装饰器提供元数据的支持
  }
}

可以显式指定需要编译的文件:

{
  "files": [
    "./some/file.ts"
  ]
}

或者, 可以使用include和exclude选项来指定需要包含的文件, 和排除的文件:

{
  "include": [
    "./folder"
  ],
  "exclude": [
    "./folder/**/*.spec.ts",
    "./folder/someSubFolder"
  ]
}

三. TypeScript类型

1、 原始类型

JavaScript原始类型也同样适应于TypeScript的类型系统, 因此string, number, boolean也可以被用作类型注解.

let bool: boolean = false;
let num: number = 10;
let str: string = 'sip';

2、数组

类型+[]

数组的项中不允许出现其他的类型:

let fibonacci: number[] = [1, '1', 2, 3, 5];

// Type 'string' is not assignable to type 'number'.

(1)数组泛型

let fibonacci: Array<number> = [1, 1, 2, 3, 5];

(2)用接口表示数组

interface NumberArray {
    [index: number]: number;
}
let fibonacci: NumberArray = [1, 1, 2, 3, 5];

3、 接口

它能合并多类型声明至一个类型声明

// 接口 Person (接口一般首字母大写)
interface Person {
    name: string;
    age: number;
}

let man: Person = {
    name: 'Tom',
    age: 25
}

(1)可选属性

可选属性的含义是该属性可以不存在,但不允许添加未定义的属性

interface Person {
    name: string;
    age?: number;
}

let man: Person = {
    name: 'Tom'
};

let man2: Person = {
    name: 'Tom',
    age: 25
};

let man3: Person = {
    name: 'Tom',
    tel: '1370000000'
};
// error TS2322: Type '{ name: string; tel: string; }' is not assignable to type 'Person'. 
// Object literal may only specify known properties, and 'tel' does not exist in type 'Person'.

(2)任意属性

一个接口中只能定义一个任意属性。

interface Person {
    name: string;
    age?: number;
    [propName: string]: any;
}

let man: Person = {
    name: 'Tom',
    gender: 'male'
};

使用 [propName: string] 定义了任意属性取 string 类型的值。

(3)只读属性

interface Person {
    readonly id: number;
    name: string;
    age?: number;
    [propName: string]: any;
}

let man: Person = {
    id: 99999,
    name: 'Tom',
    gender: 'male'
};

man.id = 10000;
// error TS2540: Cannot assign to 'id' because it is a read-only property.

4、 内联类型注解

:{/*Structure*/}

5、 特殊类型

any 它提供一个类型系统的后门, TypeScript将会把类型检查关闭.
null和undefined 能被赋予给任意类型的变量
void 表示一个函数没有返回值
let notSure: any = 'any';
notSure = 1;

变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型

let something;
// 等同于 let something: any;
function alertName(): void {
    alert('My name is Tom');
}

声明一个 void 类型的变量没有什么用,因为你只能将它赋值为 undefinednull

void 的区别是,undefinednull 是所有类型的子类型。也就是说 undefined 类型的变量,可以赋值给 number 类型的变量

// 这样不会报错
let num: number = undefined;
// 这样也不会报错
let u: undefined;
let num: number = u;

6、泛型

interface Array<T> {
  reverse(): T[];
}

7、 联合类型

联合类型(Union Types)表示取值可以为多种类型中的一种。

let strNum: string | number;
strNum = 'seven';
strNum = 7;

8、枚举

enum Color {Red, Green, Blue}       // 默认从0开始编号
let color: Color = Color.Green;

四、函数的类型

1、函数声明

function sum(x: number, y: number): number {
    return x + y;
}
// 注意,输入多余的(或者少于要求的)参数,是不被允许的:
sum(1, 2, 3);
// error TS2554: Expected 2 arguments, but got 3.
sum(1);
// error TS2554: Expected 2 arguments, but got 1.

2、函数表达式

let mySum = function (x: number, y: number): number {
    return x + y;
};

3、用接口定义函数

interface SearchFunc {
    (source: string, subString: string): boolean;
}

let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
    return source.search(subString) !== -1;
}

4、可选参数

与接口中的可选属性类似,我们用 ? 表示可选的参数,需要注意的是,可选参数必须接在必需参数后面。

function buildName(firstName: string, lastName?: string) {
    if (lastName) {
        return firstName + ' ' + lastName;
    } else {
        return firstName;
    }
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');

5、参数默认值

function buildName(firstName: string = 'Tom', lastName: string) {
    return firstName + ' ' + lastName;
}
let tomcat = buildName('Tom', 'Cat');
let cat = buildName(undefined, 'Cat');

五、组合式api

1、为组件的props标注类型

当使用 <script setup> 时,defineProps()宏函数支持从它的参数中推导类型

<script setup lang="ts">
const props = defineProps({
  foo: { type: String, required: true },
  bar: Number
})

props.foo // string
props.bar // number | undefined
</script>

然而,声明式更直接

<script setup lang="ts">
const props = defineProps<{
  foo: string
  bar?: number
}>()
</script>

另外,我们还可以将类型移入一个单独的接口中

<script setup lang="ts">
interface Props {
  foo: string
  bar?: number
}

const props = defineProps<Props>()
</script>

2、为组件的emits标注类型

<script setup lang="ts">
// 运行时
const emit = defineEmits(['change', 'update'])

// 基于类型
const emit = defineEmits<{
  (e: 'change', id: number): void
  (e: 'update', value: string): void
}>()
</script>

3、为ref()标注类型

ref 会根据初始化时的值推导其类型:

import { ref } from 'vue'

// 推导出的类型:Ref<number>
const year = ref(2020)

// => TS Error: Type 'string' is not assignable to type 'number'.
year.value = '2020'

想为 ref 内的值指定一个更复杂的类型,可以通过使用 Ref 这个类型

import { ref } from 'vue'
import type { Ref } from 'vue'

const year: Ref<string | number> = ref('2020')

year.value = 2020 // 成功!

或者,在调用 ref() 时传入一个泛型参数,来覆盖默认的推导行为:

// 得到的类型:Ref<string | number>
const year = ref<string | number>('2020')

year.value = 2020 // 成功!

4、为reactive标注类型

reactive() 也会隐式地从它的参数中推导类型

import { reactive } from 'vue'

// 推导得到的类型:{ title: string }
const book = reactive({ title: 'Vue 3 指引' })

要显式地标注一个 reactive 变量的类型,我们可以使用接口:

import { reactive } from 'vue'

interface Book {
  title: string
  year?: number
}

const book: Book = reactive({ title: 'Vue 3 指引' })

5、为computed标注类型

computed() 会自动从其计算函数的返回值上推导出类型:

import { ref, computed } from 'vue'

const count = ref(0)

// 推导得到的类型:ComputedRef<number>
const double = computed(() => count.value * 2)

// => TS Error: Property 'split' does not exist on type 'number'
const result = double.value.split('')

还可以通过泛型参数显式指定类型:

const double = computed<number>(() => {
  // 若返回值不是 number 类型则会报错
})

6、为事件处理函数标注类型

<script setup lang="ts">
function handleChange(event) {
  // `event` 隐式地标注为 `any` 类型
  console.log(event.target.value)
}
</script>

<template>
  <input type="text" @change="handleChange" />
</template>

没有类型标注时,这个 event 参数会隐式地标注为 any 类型。这也会在 tsconfig.json 中配置了 "strict": true"noImplicitAny": true 时报出一个 TS 错误。因此,建议显式地为事件处理函数的参数标注类型。此外,你可能需要显式地强制转换 event 上的属性:

function handleChange(event: Event) {
  console.log((event.target as HTMLInputElement).value)
}

7、为provide/inject标注类型

provide 和 inject 通常会在不同的组件中运行。要正确地为注入的值标记类型,Vue 提供了一个 InjectionKey 接口,它是一个继承自 Symbol 的泛型类型,可以用来在提供者和消费者之间同步注入值的类型:

import { provide, inject } from 'vue'
import type { InjectionKey } from 'vue'

const key = Symbol() as InjectionKey<string>

provide(key, 'foo') // 若提供的是非字符串值会导致错误

const foo = inject(key) // foo 的类型:string | undefined

8、为模板引用标注类型

模板引用需要通过一个显式指定的泛型参数和一个初始值 null 来创建:

<script setup lang="ts">
import { ref, onMounted } from 'vue'

const el = ref<HTMLInputElement | null>(null)

onMounted(() => {
  el.value?.focus()
})
</script>

<template>
  <input ref="el" />
</template>

9、为组件模板引用标注类型

<!-- MyModal.vue -->
<script setup lang="ts">
import { ref } from 'vue'

const isContentShown = ref(false)
const open = () => (isContentShown.value = true)

defineExpose({
  open
})
</script>

为了获取 MyModal 的类型,我们首先需要通过 typeof 得到其类型,再使用 TypeScript 内置的 InstanceType 工具类型来获取其实例类型:

<!-- App.vue -->
<script setup lang="ts">
import MyModal from './MyModal.vue'

const modal = ref<InstanceType<typeof MyModal> | null>(null)

const openModal = () => {
  modal.value?.open()
}
</script>

 




相关推荐

一、script标签属性 async 表示立即下载该脚本,但不妨碍页面中的其他操作,只对外部文件有效。 charset 与src属性一起使用,告诉浏览器用来编码这个javascript程序的

ECMAscript 5添加了第二种运行模式:严格模式(strict mode)。 //针对单个脚本 <script>   "use strict";   console.log("这是严格模式

Javascript中, !表示运算符"非", 如果变量不是布尔类型, 会将变量自动转化为布尔类型

一、基本用法 Object.assign方法用于对象的合并,将源对象的所有可枚举属性复制目标对象。 <

1、安装依赖 npm install echarts --save npm install --save @type

一、window对象 在javascript中,一个浏览器窗口就是一个window对象,window对象以及这些子对象,由于都是用于操作浏览器窗口,所以我们又称为BOM(Browser Object

Math.random()方法会返回介于0(包含)~1(不包含)之间的一个随机数。 舍掉小数点后的数值的方法有很多,如parseInt(),Math.ceil(),Math.flo

一、概述 所有语言中的代理,其本实现的是对原对象的操作的拦截和一些自定义行为。 二、语法  const p = new Proxy(target, handler) 1、target 可以是任何类型的

一、as关键字 在ts中,表示断言有两种方式: 1、扩号表示法: let someValue: any = "this is a string"; let strLength: number = (s

一、概述 函数实际上是对象,每个函数都是Function类型的实例,而且与其他引用类型一样具有属性和方法,因此函数名实际上也是一个指向函数对象的指针,因为函数名是指针,所以js没有函数重载。 func