TypeScript基础语法总结
一、部分关键字总结说明
1. extends
(1)在 JS 中,担当类的继承重担
App extends Component
(2)在 TS 类型中,当泛型约束
type ToUpper<S extends string> = xxx
(3)在 TS 类型中,条件判断的关键词
type ReturnType<T> = T extends () => infer R ? R : never'`
2. in
遍历,用于取联合类型的值,主要用于数组和对象的构造。不要用于 interface,否则会出错。
type Name = 'Tom' | 'John' | 'Sim'
type NameObj = {
[T in Name]: string
}
/**
type NameObj = {
Tom: string;
John: string;
Sim: string;
}
*/
3. keyof
获取类、对象、接口的所有属性名组成的联合类型。
type MyPerson = {
name: string;
age: number;
hobbies: string[]
}
type ToReadonly<Obj> = {
readonly [Key in keyof Obj]: Obj[Key]
}
type res = ToReadonly<MyPerson>
/**
type res = {
readonly name: string;
readonly age: number;
readonly hobbies: string[];
}
*/
4. infer
泛型与条件与类型推断变量。表示在 extends 条件语句中以占位符出现的用来修饰数据类型的关键字,被修饰的数据类型等用到的时候才能被推断出来
作用:获取参数,返回值,泛型 的类型
出现位置:参数、返回值、类型的泛型具体化类型上
type NameType<T> = T extends (param: infer P) => any ? P : T
5. 联合:|
类似于 js 里的或运算符,但作为类型,代表类型可以是几个类型之一
type Name = 'Tom' | 'John' | 'Sim'
6. 交叉:&
类似于 js 里的与运算符,但作为类型,代表对当前几个类型的合并处理
type Name1 = 'Tom' | 'John' | 'Sim'type
Name2 = 'Sim' | 'Aim'
type ResName = Name1 & Name2 // type ResName = "Sim"
二、条件语句 三元表达式
type AA = 1 extends number ? 1 : never // 1
type IsRed = 'blue' extends 'red' ? true : false // false
三、声明文件
declare var 声明全局变量
declare function 声明全局方法
declare class 声明全局类
declare enum 声明全局枚举类型
declare namespace 声明(含有子属性的)全局对象
interface 和 type 声明全局类型
export 导出变量
export default ES6默认导出
export namespace 导出(含有子属性的)对象
export = commonjs 导出模块
export as namespace UMD库声明全局变量
declare global 扩展变量
declare module 扩展模块
/// <reference /> 三斜线指令
四、基础类型
string, number, boolean, null, undefined, any, never, enum(枚举), array(数组), tuple(元组), object, void
✨ never类型是所有类型的子类型
✨ undefined 在 tsconfig strictNullChecks 为 true 的情况下是 void 和 any 类型子类型,为 false 的情况下则除 never 的子类型
1. Enum
枚举类型用于取值被限定在一定范围内的场景
enum Days {
Mon = 1,
Tue, // 2
Wed, // 3
Thu, // 4
Fri, // 5
Sat, // 6
Sun, // 7
}
let day = [Days.Sun, Days.Mon, Days.Fri] // day = [7, 1, 5]
2. Tuple
元组是个数有限、类型固定的数组类型
let tom1: readonly [string, number] = ['Tom', 25]
2.1 合并两个元组
type Concat<T extends any[], U extends any[]> = [...T, ...U]
type Res = Concat<[1], [2, 3]> // [1, 2, 3]
2.2 元组的遍历:递归方式,对象类型遍历方式
两种处理方式都能遍历到每个元素,并对每个元素做一些判断和处理。除了在会增加元素数量的情况下,必须使用递归的模式,其它情况可任选
(1)用递归思想解决元组拍平问题
type Flatten<T extends any[]> = T extends [infer First, ...infer Rest]
? (First extends any[]
? [...Flatten<First>, ...Flatten<Rest>]
: [First, ...Flatten<Rest>])
: []
type Res = Flatten<[1, [[2]]]> // [1,2]
(2) 希望 [1, () => number, string] 能够被处理成 [1, number, string]
type GetType<T extends any[]> = {
[K in keyof T]: T[K] extends () => infer R ? R : T[K]
}
type Res = GetType<[1, () => number, string]> // [1, number, string]
2.3 元组与索引与联合类型
type tupleStr = ['a', 'b', 'c']
type AAA = tupleStr[0]; // 'a'
type BBB = tupleStr[1]; // 'b'
// 因为 number 代表了可能是 0 也可能是 1 或者 2,所以这些可能性组成的集合就是联合类型
type UnionStr = tupleStr[number]; // 'a' | 'b' | 'c' 变成了联合类型
3. 字符串字面量类型
字符串字面量类型用来约束取值只能是某几个字符串中的一个
3.1 类型别名与字符串字面量类型都是使用 type 进行定义#
type EventNames = 'click' | 'scroll' | 'mousemove'
function handleEvent (ele: Element, event: EventNames) {
// do something
}
3.2 字符串操作:字符串类型推导与解构#
(1)推导类型中油字符串字面量的情况
// 实现一个将字符串类型中 _ 去除的功能,其可以为:
type DelUnderline<T extends string> = T extends `${infer LeftWords}_${infer RightWords}`
? `${LeftWords}${RightWords}`
: T
type HelloWorld = DelUnderline<'hello_world'> // helloworld(LeftWords 为 hello,RightWords 为 world)
type World = DelUnderline<'_world'> // world(LeftWords 为空字符串,RightWords 为 world)
type Hello = DelUnderline<'hello_'> // hello(LeftWords 为 hello,RightWords 为空字符串)
(2)推导类型中无字符串字面量的情况
// 实现 TS 类型的首字母大写的效果,其可以为:
type MyCapitalize<T extends string> = T extends `${infer First}${infer Rest}`
? `${Uppercase<First>}${Rest}`
: T;
type A19_2 = MyCapitalize<'hello'>; // "Hello"(First 为 "h",Rest 为 "ello")
type B = MyCapitalize<'b'>; // "B" (First 为 "h",Rest 为空字符串)
type C = MyCapitaliz
e<''>; // 当为空字符串时,会走到 false 的分支,返回空字符串
五、类型断言
// 值 as 类型 或 <类型>值
let ele = document.getElementById('id_1') as HTMLElement
六、类型守卫
-
类型判断:typeof
-
属性或者方法判断:in
-
实例判断:instanceof
-
字面量相等判断:==, ===, !=, !
七、联合类型 and 类型别名
1. 联合类型
表示取值可以为多种类型中的一种
let username: string | number = 'yyy'
当ts不确定一个联合类型的变量到底是哪个类型的时候,我们只能“访问此联合类型所有类型里共有的属性或方法”
user1.toString()
联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型
user1 = 20 // 推断成number
1.1 联合类型与泛型推导
// 例子中并不是将 'a' | 'b' | 'c' 一次性判断的,而是一个一个走的判断
type Foo<T> = T extends 'a' | 'b' ? `${T}1` : T
type Bar = Foo<'a' | 'b' | 'c'> // "a1" | "b1" | "c"
2. 类型别名
类型别名: type 既可以表示基础类型,也可以表示对象类型
type Name = string | number
let name1: Name = 123
八、函数
1. 函数的类型
function buildName(firstName: string, lastName?: string, other:string = 'default'):string {
if (lastName) {
return firstName + ' ' + lastName + other
} else {
return firstName + other
}
}
2. 用接口定义函数的形状
interface SearchFunc {
(source: string, subString: string): boolean
}
let mySearch: SearchFunc
mySearch = function (source: string, subString: string) {
return source.search(subString) !== -1
}
剩余参数 "...rest", 可选参数 "?", 默认参数 "="
function push(array: any[], name = 'yyy', age?: number, ...items: any[]) {
items.forEach(item => {
array.push(item)
})
}
九、数组
let arr1: number[] = [1,2,3,4]
let arr2: Array<string> = ['1', '2']
let arr3: any[] = [1, '2', { k: 'v' }, [0]]
十、对象
-
ECMAScript 标准内置对象:Boolean、Error、Date、RegExp等
-
DOM 和 Bom:Document、HTMLElement、Event、NodeList等
十一、接口
interface Person4 {
// 只读属性
readonly id: number
name: string
age: number
// 可选属性
sex?: string
// 任意属性取string类型的值
// 一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集
[x:string]: any
}
let tom: Person4 = {
id: 1,
name: 'Tom',
age: 20
}
十二、类
1. 基础用法
class Animal {
public name:string;
private readonly age:number;
public constructor(name:string, age: number) {
this.name = name
this.age = age
}
sayHi ():string {
return `My name is ${this.name}, age is ${this.age} years old..`
}
}
class Cat extends Animal {
constructor(name, age) {
super(name, age)
}
sayHi(): string {
return super.sayHi()
}
}
2. 类与接口
2.1 类实现接口
interface Alarm {
alert():void
}
interface Light {
lightOn():void
lightOff():void
}
class Car implements Alarm, Light {
alert(): void {
console.log('car alert')
}
lightOn(): void {
console.log('car lightOn')
}
lightOff(): void {
console.log('car lightOff')
}
}
2.2 接口继承接口
// LightableAlarm 继承了 Alarm,除了拥有 alert 方法之外,还拥有两个新方法 lightOn 和 lightOff
interface Alarm {
alert():void
}
interface LightableAlarm extends Alarm {
lightOn():void
lightOff():void
}
2.3 接口继承类
在接口继承类的时候,也只会继承它的实例属性和实例方法
class Point {
x: number
y: number
constructor(x: number, y: number) {
this.x = x
this.y = y
}
fn () {
console.log('fn...')
}
}
interface Point3d extends Point {
z: number
}
let point3d: Point3d = {
x: 1,
y: 2,
z: 3,
fn() {
console.log('fn~', )
},
}
十三、泛型
泛型 (-类型中的函数) 是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
function createArray<T>(length:number, value: T): Array<T> {
let result: T[] = []
for (let i = 0; i < length; i++) {
result[i] = value
}
return result
}
1. 泛型接口
interface CreateArrayFunc {
<T>(length:number, value: T): Array<T>
}
let createArray2: CreateArrayFunc
2. 泛型类 泛型参数带默认类型
class GenericNumber<T = string> {
zeroValue: T;
add: (x:T, y:T) => T
}
let myGenericNumber = new GenericNumber<number>()
myGenericNumber.zeroValue = 1
myGenericNumber.add = (x, y) => x + y
3. 泛型约束
对输入参数进行校验,泛型中通过 extends 关键字实现
class Per {
name: string;
}
function getName(user) {
if (!(user instanceof Per)) {
throw new Error(`${user} is not instanceof "Person"`);
}
return user.name;
}
type GetName<U extends Person> = U['name']
4. 泛型与条件判断
type IsBoolean<T> = T extends boolean ? true : false;
type AA = IsBoolean<true>; // true
type BB = IsBoolean<1>; // false
5. 泛型与条件与类型推断变量 infer
type ReturnType1<T> = T extends ((...args: any) => infer R) ? R : never;
type GetSum = (a: number, b: number) => number;
type A1 = ReturnType<GetSum> // number
6. ts内置泛型工具
// 1> Pick 挑选出指定属性,生成新对象类型
type UserInfo = Pick<Person, 'name' | 'age'>; // 挑选出 { name: string; age: number }
// 2> Omit 排除指定的属性,生成新的对象类型
type UserInfo2 = Omit<Person, 'id'>; // 排除 id,生成 { name: string; age: number }
// 3> Partial 将对象所有属性变为可选
type PartialPerson = Partial<Person>; // { name?: string; age?: number; id?: number }
// 4> Readonly 将对象所有属性变为只读
type ReadonlyPerson = Readonly<Person>; // { readonly name: string; readonly age: number; readonly id: number }
// 5> Record 生成对象类型,例如
type PersonMap = Record<number, Person>; // { [index: number]: Person }
// 6> Exclude 排除一些联合类型
type UserInfoKeys = Exclude<keyof Person, 'id'>; // 'name' | 'age'
十四、声明合并
1. 函数的合并
function reverse(x:number):number
function reverse(x:string):string
function reverse(x: number | string): number | string {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('')
}
return 0
}
2. 接口的合并
interface Alarm2 {
price: number
alert(s: string): string
}
interface Alarm2 {
weight: number
alert(s: string, n: number): string
}
// 想当于
interface Alarm2 {
price: number
weight: number
// 接口中方法的合并,与函数的合并一样
alert(s: string): string
alert(s: string, n: number): string;
}
类的合并 类的合并与接口的合并规则一致
十五、其他
// 从 js 值转为 ts 值
const jack1 = {
name: 'jack',
age: 18
}
// 从 JS 中获取 TS 并赋值
type Person20 = typeof jack1; // 此时 Person 为 { name: string; age: number }
// 使用到 as const 语法,让其尽可能精准的推测
const jack2 = {
name: 'jack',
age: 18
} as const; // 会被推导为:{ readonly name: "jack"; readonly age: 18; }
const arr = [1, 2] as const; // 会被推导为:readonly [1, 2];