TypeScript内置数据类型
日常的数据类型
ts 是 js 的超集,所以 js 中这些 number、boolean、string、object、bigint、symbol、undefined、null 类型 ts 都是支持的。
除此之外 ts 中新增了这些类型:
Interfaces (接口)
可以描述函数、对象、构造器的结构:
interface Point {
x: number
y: number
}
function printCoord(pt: Point) {
console.log("The coordinate's x value is " + pt.x)
console.log("The coordinate's y value is " + pt.y)
}
interface SayHello {
(name: string): string
}
const func: SayHello = (name: string) => {
return `hello,${name}`
}
我们也可以使用 type(类型别名)来实现上面相同的功能
type Point = {
x: number
y: number
}
// Exactly the same as the earlier example
function printCoord(pt: Point) {
console.log("The coordinate's x value is " + pt.x)
console.log("The coordinate's y value is " + pt.y)
}
可以使用类型别名为任何类型命名,而不仅仅是对象类型。例如,类型别名可以命名联合类型:
type ID = number | string
类型别名和接口非常相似,在许多情况下,可以在它们之间自由选择。几乎所有 interface 的功能都可用 type ,关键的区别在于类型不能重新定义添加新属性,而接口始终是可扩展的。
interface Animal {
name: string
}
interface Bear extends Animal {
honey: boolean
}
// 等同于
type Animal = {
name: string
}
type Bear = Animal & {
honey: boolean
}
const bear = getBear()
bear.name
bear.honey
区别
interface Window {
title: string
}
interface Window {
ts: TypeScriptAPI
}
const src = 'const a = "Hello World"'
window.ts.transpileModule(src, {})
// 类型创建后无法更改
type Window = {
title: string
}
type Window = {
ts: TypeScriptAPI
}
// Error: Duplicate identifier 'Window'.
Enums(枚举)
枚举是一系列值的复合
enum Direction {
Up = 1,
Down,
Left,
Right,
}
const up = Direction.Up // 1
其中 Up 初始化为 1 。从那时起,以下所有成员都将自动递增。换言之, Direction.Up 具有值 1 、 Down 、 2 Left 、 3 和 Right 具有 4 。
Tuple(元组)
元组(Tuple)就是元素个数和类型固定的数组类型:
type Tuple = [number, string]
其他类型
- never 代表不可达,比如函数抛异常的时候,返回值就是 never,never 可以分配给一切。没有任何东西可以分配给 never。
- void 对于没有记录返回值的函数。
- any 是任意类型,任何类型都可以赋值给它,它也可以赋值给任何类型(除了 never)。
- unknown 是未知类型,任何类型都可以赋值给它,但是它不可以赋值给别的类型。
内置高级数据类型
Partial(部分的)
Partial<Type>
构造一个类型,将传入的 Type 属性都设置为可选。返回一个类型,该类型表示给定类型的所有子集。
interface Todo {
title: string
description: string
}
type PartialTodo = Partial<Todo>
const tode1: PartialTodo = {
title: 'Todo Title',
}
const tode2: PartialTodo = {
description: 'Todo description',
}
上面Partial
将Todo
类型里面的所有属性都变成可选类型.
Required(必须的)
与Partial
相反,Required<Type>
将传入的类型属性都设置为必填的.
interface Props {
age?: number
name?: string
}
type RequiredProps = Required<Props>
const RequiredProps: RequiredProps = {
age: 18,
name: 'required',
}
上面Required
将Props
类型里面的所有属性都变成必填类型.
Readonly(只读)
Readonly<Type>
将传入的类型属性都设置为只读的.
interface Todo {
title: string
}
const todo: Readonly<Todo> = {
title: 'Delete inactive users',
}
todo.title = 'Hello' // 报错
// Cannot assign to 'title' because it is a read-only property.
// 源码
type Readonly<T> = {
readonly [K in keyof T]: T[K]
}
上面Readonly
将Todo
类型里面的所有属性都变成只读类型,重新赋值 ts 会提示错误.
Record(记录)
Record<Keys, Type>
构造一个属性键为 Keys、属性值为 Type 的对象类型。该工具可用于将一个类型的属性映射到另一个类型。
interface CatInfo {
age: number
breed: string
}
type CatName = 'miffy' | 'boris' | 'mordred'
type catType = Record<CatName, CatInfo>
const cats: catType = {
miffy: { age: 10, breed: 'Persian' },
boris: { age: 5, breed: 'Maine Coon' },
mordred: { age: 16, breed: 'British Shorthair' },
}
新类型catType
是一个对象类型他的属性都为CatInfo
.通常使用该工具类型构造对象类型.
Pick(选择)
Pick<Type, Keys>
通过从 Type 中选取属性 Keys 集来构造类型。
interface Todo {
title: string
description: string
completed: boolean
}
type TodoPreview = Pick<Todo, 'title' | 'completed'>
const todo: TodoPreview = {
title: 'Clean room',
completed: false,
}
// 源码
type MyPick<T, K extends keyof T> = {
[P in K]: T[K]
}
这里只选择了Todo
类型里面的title
和completed
类型.
Omit(删除)
Omit<Type, Keys>
删除 Type 中含有的属性 Keys 集来构造类型。
interface Todo {
title: string
description: string
completed: boolean
createdAt: number
}
type TodoInfo = Omit<Todo, 'completed' | 'createdAt'>
const todoInfo: TodoInfo = {
title: 'Pick up kids',
description: 'Kindergarten closes at 5pm',
}
这里删除了Todo
类型里面的completed
和createdAt
类型,所以TodoInfo
只剩下title
和description
类型.
Exclude(排除)
Exclude<T,U>
留下两个类型中不同的,类似于差集
type T0 = Exclude<'a' | 'b' | 'c', 'a' | 'c'>
// "b"
type T2 = Exclude<string | number | (() => void), Function>
// string | number
Extract(提取)
Extract<T,U>
留下两个类型中相同的,类似于交集
type T0 = Extract<'a' | 'b' | 'c', 'a' | 'c'>
// "a" | "c"
type T2 = Extract<string | number | (() => void), Function>
// () => void
注意Exclude,Extract是使用在联合类型上面的,而Pick和Omit使用在对象或者 interface 上面的.
NonNullable(不为 null 和 undefined)
NonNullable<Type>
通过排除 null 和 undefined 从 Type 来构造类型。
type T1 = NonNullable<boolean | null | undefined>
// boolean
Parameters(参数)/ReturnType(返回类型)
Parameters<Type>
和ReturnType<Type>
可以得到一个函数的参数类型和返回值类型.
declare function f1(a: number, b: string): void
type AddParams = Parameters<typeof f1> // [number, string] 类型
type AddResult = ReturnType<typeof f1> // void 类型
// 源码
type Parameters<T extends (...args: any) => any> = T extends (
...args: infer P
) => any
? P
: never
type ReturnType<T extends (...args: any) => any> = T extends (
...args: any
) => infer R
? R
: any
Awaited(等待)
Awaited<Type>
获取异步函数的返回类型.
const promise = new Promise<string>((resolve) => {
resolve('hello')
})
type promiseType = Awaited<typeof promise> // string
字符串操作类型
Uppercase
Uppercase<Type>
将字符串中的每个字符转换为大写版本。
type Greeting = 'Hello, world'
type ShoutyGreeting = Uppercase<Greeting> // "HELLO, WORLD"
type ASCIICacheKey<Str extends string> = `ID-${Uppercase<Str>}`
type MainID = ASCIICacheKey<'my_app'> // ID-MY_APP
Lowercase
Lowercase<Type>
将字符串中的每个字符转换为等效的小写字符。
type Greeting = 'Hello, world'
type ShoutyGreeting = Lowercase<Greeting> // "hello, world"
type ASCIICacheKey<Str extends string> = `id-${Lowercase<Str>}`
type MainID = ASCIICacheKey<'MY_APP'> // id-my_app
这里的extends对传入的 Str 做了约束只能是 string 类型.
Capitalize
Capitalize<Type>
将字符串中的第一个字符转换为大写等效字符。
type Greeting = 'hello, world'
type ShoutyGreeting = Capitalize<Greeting> // "Hello, world"
Uncapitalize
Uncapitalize<Type>
将字符串中的第一个字符转换为等效的小写字符。
type Greeting = 'Hello, world'
type ShoutyGreeting = Uncapitalize<Greeting> // "hello, world"
类型运算
条件类型(Conditional Types)
extends 可以通过两种方式使用
当 extends 左边的类型可以赋值给右边的类型时,返回第一个类型,否则返回第二个类型(:后面的).
type res<T> = T extends string ? string : number
type res1 = res<string> // string
type res2 = res<boolean> // number
分配条件类型
当传入的类型参数为联合类型时,他们会被 分配类型 。 以下面的例子为例:
type ToArray<Type> = Type extends any ? Type[] : never
// 如果我们将联合类型传入 ToArray,则条件类型将应用于该联合类型的每个成员。
type StrArrOrNumArr = ToArray<string | number>
// type StrArrOrNumArr = string[] | number[]
通常,分布性是所需的行为。 要避免这种行为,可以用方括号括起 extends 关键字的两边。
type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never
// 'StrOrNumArr' 不再是一个联合类型
type StrOrNumArr = ToArrayNonDist<string | number>
// type StrOrNumArr = (string | number)[]
举个例子
type A = 'a' | 'b' | 'c'
type B = 'a' | 'd'
type MyExclude<T, U> = T extends U ? never : T
type C = MyExclude<A, B>
// 等同于
type C =
| ('a' extends 'a' | 'd' ? never : 'a')
| ('b' extends 'a' | 'd' ? never : 'b')
| ('c' extends 'a' | 'd' ? never : 'c')
// type C = 'c'
这也是Exclude
的实现方式
infer (推导)
提取类型的一部分,示例获取参数类型
type argType<T> = T extends (...args: infer P) => any ? P : never
type Fn = argType<(a: number, b: string) => number>
// type Fn = [a: number, b: string]
联合:|
类型可以是后面几个类型之一,有点类似于或运算
type res = number | string
交叉:&
同一类型可以合并,不同的类型没法合并,会被舍弃:
type Combined = { a: number } & { b: string }
// 此时 Combined 具有两个属性, a 并且 b
type res = number & string
// res = never
// 没有一个类型即是number 也是 string. 所以ts推断为never,表示没有可能的值。
映射类型
如 Partial 源码,将所有类型变成可选类型.
type Partial<T> = {
[Key in keyof T]?: T[Key]
}
type res = Partial<{
a: string
b: number
}>
// type res = {
// a?: string | undefined;
// b?: number | undefined;
// }
keyof: 取 interface 的键后保存为联合类型
interface userInfo {
name: string
age: number
}
type keyofValue = keyof userInfo
// keyofValue = "name" | "age"
T[Key] 是取索引类型某个索引的值,叫做索引访问。
in: 取联合类型的值,主要用于数组和对象的构建
type name = 'firstname' | 'lastname'
type TName = {
[key in name]: string
}
// TName = { firstname: string, lastname: string }