数组定义方式
const a: number[] = [1]
const a: Array<number> = [1]
undefined和null
undefined和null是所有类型的子集,可以把他们赋值给任何类型。但是在严格模式下不可以:
tsconfig.json:
"strictNullChecks":true
严格模式下的特例:
const a:void = undefined
unknown和any
unknown和any都可接受任何类型的赋值,但是any可以赋值给任何类型,unknown只能赋值给unknown和any
可选参数与默认参数
const a = (pramas?: string) => {
console.log(pramas) // 可能是undefined
}
const b = (params: string = "bbb") => {
console.log(params) // "bbb"
}
函数重载
在没有弱类型的js语言中,定义同名函数编译是会直接报错的,但是由于ts在定义函数的时候指定了类型,所以可以支持函数重载啦。 函数重载指的是接受同名,但是指定了不同类型入参的函数,返回的结果根据入参的不同而不同。
但是在写函数重载时,需要注意的是在最后一个重载函数书写完毕之前,都不能写具体函数体。
function a(i: number, j: number):number
function a(i: string, j: string): string
function a(i: string, j: number): string {
return i + j
}
但是这种情况我直接写any或者T它不香吗?(狗头
类型断言
如果在声明变量时用到了any或者unknown, 但是在使用时又明确这个变量的类型,可以使用类型断言: as 或 <>
const a: any = "a,b"
console.log((a as string).split(",")[0]) // a
console.log((<string>a).split(",")[0]) // a
类型交叉
如果实际使用中,需要同时用到两种接口(interface),可以使用&定义交叉类型:
interface a {
color: string,
width: number
}
interface b {
width: number,
height: number,
}
const a: a&b = {
color: "red",
width: 100,
height: 100
}
上述代码如果两个width定义的类型不同,a&b后会直接给width定义为never。
泛型
泛型的作用是当定义一个类/接口/类型/函数时,确定但不完全确定类型时,可以通过泛型去定义,通常用T代表泛型,但这只是通常,起其他名字也没毛病。
举个例子,当一个函数入参可能是number | string | Array,返回类型与之对应时,可以使用泛型去限制:
function a<T>(params: T): T => {
return params
}
a<string>("i'm string")
可以将泛型理解为另一种函数入参数,只不过这个参数只代表类型。
泛型也可以使用extends关键字继承
当定义泛型时不知道具体类型,但期望其中有一些属性是固定的,可以通过extends实现
interface IA {
age: number
}
function a<T extends IA>(person: T): T {
return person
}
a<{
sex: string,
age: number
}>({
sex: "man",
age: 18
})
/* {
sex: "man",
age: 18
} */
泛型定义类
class a<T>{
age: T;
getAge: (person: string):T
}
const newA = new a<number>()
a.age = 18;
泛型定义接口
interface IA<T, U> {
age: T,
tall: T,
name: U
}
const a:IA<number, string> = {
age: 18,
tall: 180,
name: "HHG"
}
泛型定义type
type TA<T, U> = {
name: T,
age: U
}
const a: TA<string, number> = {
name: "HHG",
age: 18
}
访问interface中的属性
interface a {
name: string,
age: number
}
type b = a["name"] // type b = string
extends和implements
extends 继承
继承就是子继承父的属性。
- 类可以继承类
class a {
name: string
}
class b extends a {
age: number
}
const newB = new b({
name: "HHG",
age: 18
})
- 接口可以继承类
class a {
name: string
}
interface b extends a {
age: number
}
const newB = new b({
name: "HHG",
age: 18
})
- 接口可以继承接口
interface a {
name: string
}
interface b extends a {
age: number
}
const user:b = {
name: "HHG",
age: 18
}
implements 实现
implements只能用于class,也就是说只存在类实现接口或者类实现类。
- 类实现接口
interface a {
say: <T>(name: T):T
}
class b implements a {
name: string,
say: <T>(name: T): T => {
console.log(name)
}
}
- 类实现类
class a {
say: <T>(name: T):T => {
console.log(name)
return name
}
}
class b implements a {
say: <T, U>(name: T, age: U): void => {
console.log(name, age)
}
}
tsconfig.json和.d.ts
这是两个ts配置文件。
.d.ts
.d.ts的作用主要是在项目祖宗文件夹下定义全局的类型变量,并且在项目中不需要import就可以访问到。 实现上述功能还需要在tsconfig.json中的include中添加该文件,通常叫typings.d.ts
{
"include": [
"typings.d.ts"
]
}
declare
declare声明,在.d.ts文件中最外层的声明都需要加上declare或export,保证在项目内可以访问到。
在.d.ts中通常需要声明一些模块来避免因为不是js/ts语言类型的文件而导致的报错
declare module '*.css';
declare module '*.scss';
declare module '*.sass';
declare module '*.svg';
declare module '*.png';
declare module '*.jpg';
declare module '*.jpeg';
declare module '*.gif';
declare module '*.bmp';
declare module '*.tiff';
declare module 'omit.js';
declare还可以在.d.ts中声明一些没有ts的库避免报错。
declare module 'jquery';
declare还可以在.d.ts中声明全局变量,如react的node环境变量
declare const REACT_APP_ENV: string;
declare也可以声明全局都要频繁使用的类型,在项目中可以不需要引入就能使用
declare type = {
name: string,
age: number
}
还可以在模块内部再声明变量:
declare module '*.less' {
const Style: Record<string, string>;
export default Style;
}
import Style from "xxx.less"
<div className={Style.aaa}>
// todo something
</div>
// types/foo-bar.d.ts
declare module 'foo' {
export interface Foo {
foo: string;
}
}
declare module 'bar' {
export function bar(): string;
}
// src/index.ts
import { Foo } from 'foo';
import * as bar from 'bar';
let f: Foo;
bar.bar();
declare就是告诉TS编译器你担保这些变量和模块存在,并声明了相应类型,编译的时候不需要提示错误!
tsconfig.json
编译配置 compilerOptions
{
"compilerOptions": {
"target": "es5", // 输出代码类型,默认es3, 可选:`"ES5"`, `"ES6"`/ `"ES2015"`, `"ES2016"`, `"ES2017"`或 `"ESNext"`。
"module": "esnext", // 指定生成哪个模块系统代码: `"None"`, `"CommonJS"`, `"AMD"`, `"System"`, `"UMD"`, `"ES6"`或 `"ES2015"`。 只有 `"AMD"`和 `"System"`能和 `--outFile`一起使用。`"ES6"`和 `"ES2015"`可使用在目标输出为 `"ES5"`或更低的情况下。
"moduleResolution": "node", // 决定如何处理模块。或者是`"Node"`对于Node.js/io.js,或者是`"Classic"`(默认)。查看[模块解析](https://www.tslang.cn/docs/handbook/module-resolution.html)了解详情。
"removeComments": false, // 删除所有注释,除了以 `/!*`开头的版权信息。
"importHelpers": true, // 从 tslib导入辅助工具函数(比如 `__extends`, `__rest`等)
"jsx": "react", // 在 `.tsx`文件里支持JSX: `"React"`或 `"Preserve"`。查看 [JSX](https://www.tslang.cn/docs/handbook/jsx.html)。
"esModuleInterop": true, // 决定import的方式,如该项为false 就需要这么写:import * as React from 'react'
"sourceMap": true, // 编译前后文件的映射
"baseUrl": "./", // import时相对路径的起点(前缀),可以配合paths使用
"strict": false, // 是否开启严格模式
"paths": { // 路径别名映射
"@/*": [
"client/*"
]
},
"allowSyntheticDefaultImports": true // 与esModuleInterop配合使用,详情见:https://jishuin.proginn.com/p/763bfbd7a69f
}
}
文件配置
files
files表示需要对项目中哪些文件进行编译(根据编译规则compilerOptions进行编译),files中声明的文件只是入口文件。
但是当我们完成大型项目时,往往是有很多文件需要编译的,这时候可以用到include和exclud
include和exclud
include:表示包含这些文件的进行编译 exclud:表示编译时排除这些文件
- exclude只对include有效,对files无效 声明时可以使用通配符:
*匹配0或多个字符(不包括目录分隔符)?匹配一个任意字符(不包括目录分隔符)**/递归匹配任意子目录
比如想要让.d.ts中的声明全局访问, 就需要对其进行编译
"includes": [
"*.d.ts"
],
比如想要编译src目录下的所有文件
"includes": [
"src/*"
],
-
如果 files 和 include 都未设置,那么除了 exclude 排除的文件,编译器会默认包含路径下的所有 TS 文件