typescript keyof
查找类型
interface Person {
name: string
age: number
location: string
}
type K1 = keyof Person // "name" | "age" | "location" 索引类型
type P2 = Person['name' | 'age'] // string | number 索引访问类型
interface Person {
name: string
age: number
location: string
}
type K1 = keyof Person // "name" | "age" | "location" 索引类型
type P2 = Person['name' | 'age'] // string | number 索引访问类型
索引类型查询keyof T
产生的类型是T
的属性名称。与之相对应的是索引访问类型,也称为查找类型
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key] // 推断类型是T[K]
}
function setProperty<T, K extends keyof T>(obj: T, key: K, value: T[K]) {
obj[key] = value
}
const x = { foo: 10, bar: 'hello!' }
const foo = getProperty(x, 'foo') // number
setProperty(x, 'foo', 'string') // 错误!, 类型是number而非string
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key] // 推断类型是T[K]
}
function setProperty<T, K extends keyof T>(obj: T, key: K, value: T[K]) {
obj[key] = value
}
const x = { foo: 10, bar: 'hello!' }
const foo = getProperty(x, 'foo') // number
setProperty(x, 'foo', 'string') // 错误!, 类型是number而非string
映射类型
interface PartialPerson {
name?: string
age?: number
location?: string
}
type Partial<T> = {
[P in keyof T]?: T[P];
}
type PartialPerson = Partial<Person>
interface PartialPerson {
name?: string
age?: number
location?: string
}
type Partial<T> = {
[P in keyof T]?: T[P];
}
type PartialPerson = Partial<Person>
// 保持类型相同,但每个属性是只读的。
type Readonly<T> = {
readonly [P in keyof T]: T[P];
}
// 保持类型相同,但每个属性是只读的。
type Readonly<T> = {
readonly [P in keyof T]: T[P];
}
Partial
和Readonly它
们现在默认包含在标准库中。
我们还包括两个其他实用程序类型:Record
和Pick
。
// 从T中选取一组属性K
declare function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K>
const nameAndAgeOnly = pick(person, 'name', 'age') // { name: string, age: number }
// 对于类型T的每个属性K,将其转换为U
function mapObject<K extends string | number, T, U>(obj: Record<K, T>, f: (x: T) => U): Record<K, U>
const names = { foo: 'hello', bar: 'world', baz: 'bye' }
const lengths = mapObject(names, s => s.length) // { foo: number, bar: number, baz: number }
// 从T中选取一组属性K
declare function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K>
const nameAndAgeOnly = pick(person, 'name', 'age') // { name: string, age: number }
// 对于类型T的每个属性K,将其转换为U
function mapObject<K extends string | number, T, U>(obj: Record<K, T>, f: (x: T) => U): Record<K, U>
const names = { foo: 'hello', bar: 'world', baz: 'bye' }
const lengths = mapObject(names, s => s.length) // { foo: number, bar: number, baz: number }
Typescript in keyof extends keyof
https://github.com/Microsoft/TypeScript/issues/10485
The in
operator could trivially be seen as a type guard:
interface A {
x: number;
}
interface B {
y: string;
}
let q: A | B = ...;
if ('x' in q) {
// q: A
} else {
// q: B
}
interface A {
x: number;
}
interface B {
y: string;
}
let q: A | B = ...;
if ('x' in q) {
// q: A
} else {
// q: B
}
Basically, for a n in x
where n
is a string literal or string literal type and x
is a union type, the "true" arm narrows to types which have an optional or required property n
, and the "false" arm narrows to types which have an optional or missing property n
.
<T, K extends keyof T>
K
can therefor only be a public property name of T
.
[K in keyof T]
in
is used when we're defining an index signature that we want to type with a union of string, number or symbol literals. In combination with keyof
we can use it to create a so called mapped type, which re-maps all properties of the original type.
type Partial<T> = {
[P in keyof T]?: T[P];
}
// 理解符号[] index signature arr[0] obj['name']
type Partial<T> = {
[P in keyof T]?: T[P];
}
// 理解符号[] index signature arr[0] obj['name']