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而非stringfunction 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']