Skip to content

关键字与语法

类型层全部的"语法关键字"。数量很少——背熟之后看任何库源码都不会有生词。

取与查

keyof关键字

取类型的所有键,返回字面量联合。

ts
interface Todo {
  
title
: string
done
: boolean
} type
K
= keyof Todo
type
A
= keyof any

带索引签名时会多出 numberkeyof { [k: string]: number }string | number

typeof关键字

把值提升成类型,是值层通往类型层的唯一入口。

ts
const 
cfg
= {
host
: 'a.com',
port
: 443 } as
const
type
Cfg
= typeof
cfg
type
Host
= typeof
cfg
['host']
索引访问 T[K]语法

类型层的查表。K 是联合时得到值的联合。

ts
interface Todo {
  
title
: string
done
: boolean
} type
A
= Todo['title']
type
B
= Todo['title' | 'done']
type
C
= [1, 2, 3]['length']
type
D
= string[]['length']

推导与遍历

infer关键字

在条件类型的 extends 子句里声明待推断变量——类型层的解构。

ts
type 
Return
<
T
> =
T
extends (...
a
: any[]) => infer
R
?
R
: never
type
First
<
T
extends unknown[]> =
T
extends [infer
F
, ...infer
_
] ?
F
: never
type
Unwrap
<
T
> =
T
extends
Promise
<infer
U
> ?
U
:
T
type
A
=
First
<[1, 2, 3]>

TS 4.8+ 支持带约束:infer R extends string

in(映射类型)关键字

类型层唯一的循环。

ts
type 
Obj
<
K
extends string> = { [
P
in
K
]: number }
type
A
=
Obj
<'a' | 'b'>
type
Nullable
<
T
> = { [
K
in keyof
T
]:
T
[
K
] | null }

用在元组上会保持长度。

as(键重映射)TS 4.1

改写键名;返回 never 可丢弃该键。

ts
type 
Getters
<
T
> = {
[
K
in keyof
T
as `get${
Capitalize
<
K
& string>}`]: () =>
T
[
K
]
} type
A
=
Getters
<{
name
: string }>

修饰与断言

as const语法

把字面量收窄到最窄并加 readonly。

ts
const 
a
= {
x
: 1,
y
: 'p' }
const
b
= {
x
: 1,
y
: 'p' } as
const
type
TA
= typeof
a
type
TB
= typeof
b
satisfiesTS 4.9

校验但保留推导结果,解决标注擦宽 / 断言不校验的两难。

ts
const 
r
= {
home
: '/',
about
: '/about' } satisfies
Record
<string, string>
type
H
= typeof
r
.
home

as const 组合时顺序固定:as const satisfies T

修饰符 + / -语法
ts
type Partial<T>  = { [K in keyof T]?: T[K] }              // 加 ?
type Required<T> = { [K in keyof T]-?: T[K] }             // 删 ?
type Readonly<T> = { readonly [K in keyof T]: T[K] }      // 加 readonly
type Mutable<T>  = { -readonly [K in keyof T]: T[K] }     // 删 readonly

修饰符是保留的,不是覆盖的。

is(类型谓词)关键字

让函数在返回 boolean 的同时收窄调用方。

ts
function 
isStr
(
x
: unknown):
x
is string {
return typeof
x
=== 'string'
} declare const
v
: unknown
if (
isStr
(
v
)) {
v
.
toUpperCase
()
}

更强版本是 asserts x is T(断言函数),收窄整个后续作用域。

模板字面量类型TS 4.1
ts
type 
World
= `hello ${'world' | 'ts'}`
type
Split
<
S
extends string> =
S
extends `${infer
A
}-${infer
B
}` ? [
A
,
B
] : [
S
]
type
R
=
Split
<'a-b'>

${infer X} 是非贪婪匹配。

进阶

in / out 变型注解TS 4.7
ts
interface Producer<out T> { get(): T }   // 只出现在输出位置
interface Consumer<in T>  { put(x: T): void } // 只出现在输入位置

标反会报错;标注正确能让 TS 跳过结构化比较,检查更快。

const 类型参数TS 5.0
ts
declare function 
f1
<
T
>(
x
:
T
[]):
T
[]
declare function
f2
<const
T
>(
x
:
T
[]):
T
[]
const
a
=
f1
(['x', 'y'])
type
A
= typeof
a
const
b
=
f2
(['x', 'y'])
type
B
= typeof
b
NoInfer<T>TS 5.4

阻止类型参数参与推断,只用于校验。

ts
declare function 
f
<
T
>(
items
:
T
[],
init
:
NoInfer
<
T
>):
T
// init 不会把 T 推宽,只做校验
unique symbol关键字

配合交叉类型做 branded type。

ts
declare const 
brand
: unique symbol
type
UserId
= string & { readonly [
brand
]: 'UserId' }
type
PostId
= string & { readonly [
brand
]: 'PostId' }
declare const
uid
:
UserId
declare const
pid
:
PostId
// uid = pid 会报错

下一步

基于 VitePress 与 Twoslash 构建