Item 56: Pay Attention to How Types Display
要点
- There are many valid ways to display the same type. Some are clearer than others.
- TypeScript gives you some tools to control how types display, notably the
Resolve
generic. Make judicious use of this to clarify type display and hide implementation details. - Consider handling important special cases of generic types to improve type display.
- Write tests for your generic types and their display to avoid regressions.
- 展示同一类型的方式有很多种,某些方式比其他方式更清晰。
- TypeScript 提供了一些控制类型显示的工具,特别是
Resolve
泛型。要谨慎使用它来澄清类型显示并隐藏实现细节。 - 考虑处理泛型类型的重要特殊情况,以改善类型显示。
- 为你的泛型类型及其显示编写测试,以避免回归错误。
正文
ts
type T123 = '1' | '2' | '3'
// ^? type T123 = "1" | "2" | "3"
ts
type T21 = '2' | '1'
// ^? type T21 = "2" | "1"
type T123 = '1' | '2' | '3'
// ^? type T123 = "2" | "1" | "3"
ts
type PartiallyPartial<T, K extends keyof T> = Partial<Pick<T, K>> & Omit<T, K>
ts
interface BlogComment {
commentId: number
title: string
content: string
}
type PartComment = PartiallyPartial<BlogComment, 'title'>
// ^? type PartComment =
// Partial<Pick<BlogComment, "title">> &
// Omit<BlogComment, "title">
ts
type Resolve<T> = T extends Function ? T : { [K in keyof T]: T[K] }
ts
type PartiallyPartial<T, K extends keyof T> = Resolve<
Partial<Pick<T, K>> & Omit<T, K>
>
type PartComment = PartiallyPartial<BlogComment, 'title'>
// ^? type PartComment = {
// title?: string | undefined;
// commentId: number;
// content: string;
// }
ts
type ObjIdentity<T> = { [K in keyof T]: T[K] }
ts
type S = ObjIdentity<string>
// ^? type S = string
type N = ObjIdentity<number>
// ^? type N = number
type U = ObjIdentity<'A' | 'B' | 'C'>
// ^? type U = "A" | "B" | "C"
ts
type F = ObjIdentity<(a: number) => boolean>
// ^? type F = {}
ts
type D = Resolve<Date>
// ^? type D = {
// toLocaleString: {
// (locales?: Intl.LocalesArgument,
// options?: Intl.DateTimeFormatOptions | undefined): string;
// (): string;
// (locales?: string | string[] | undefined,
// options?: Intl.DateTimeFormatOptions | undefined): string;
// };
// ... 42 more ...;
// [Symbol.toPrimitive]: {
// ...;
// };
// }
ts
interface Color {
r: number
g: number
b: number
a: number
}
type Chan = keyof Color
// ^? type Chan = keyof Color
type ChanInline = Resolve<keyof Color>
// ^? type ChanInline = "r" | "g" | "b" | "a"
ts
type FullComment = PartiallyPartial<BlogComment, never>
// ^? type FullComment = {
// title: string;
// commentId: number;
// content: string;
// }
ts
type PartiallyPartial<T extends object, K extends keyof T> = [K] extends [never]
? T // special case
: T extends unknown // extra conditional to preserve distribution over unions
? Resolve<Partial<Pick<T, K>> & Omit<T, K>>
: never
type FullComment = PartiallyPartial<BlogComment, never>
// ^? type FullComment = BlogComment