https://dev.to/ibrahima92/advanced-typescript-types-cheat-sheet-with-examples-5414 转载
1 交集类型
是一种将多种类型组合为一种类型的方法。这意味着您可以将给定的类型a与类型B或更多合并,并获得具有所有属性的单一类型。
type LeftType = {
id: number
left: string
}
type RightType = {
id: number
right: string
}
type IntersectionType = LeftType & RightType
function showType(args: IntersectionType) {
console.log(args)
}
showType({ id: 1, left: "test", right: "test" })
// Output: {id: 1, left: "test", right: "test"}
如您所见,IntersectionType结合了两种类型——LeftType和RightType,并使用&符号来构造交集类型。
2 联合类型 允许在给定变量中拥有不同的类型注释。
type UnionType = string | number
function showType(arg: UnionType) {
console.log(arg)
}
showType("test")
// Output: test
showType(7)
函数showType是一个联合类型,接受字符串和数字作为参数
3 泛型类型 是重用给定类型的一部分的一种方式。它有助于捕获作为参数传入的类型T。
function showType<T>(args: T) {
console.log(args)
}
showType("test")
// Output: "test"
showType(1)
// Output: 1
要构造泛型类型,需要使用方括号并将T作为参数传递。
这里,我使用T(名称由您决定),然后使用不同的类型注释调用函数showType两次,因为它是泛型的——它可以重用。
interface GenericType<T> {
id: number
name: T
}
function showType(args: GenericType<string>) {
console.log(args)
}
showType({ id: 1, name: "test" })
// Output: {id: 1, name: "test"}
function showTypeTwo(args: GenericType<number>) {
console.log(args)
}
showTypeTwo({ id: 1, name: 4 })
// Output: {id: 1, name: 4}
这里,我们有另一个例子,它有一个接口GenericType,它接收一个泛型类型t。由于它是可重用的,我们可以先用一个字符串,然后用一个数字来调用它
interface GenericType<T, U> {
id: T
name: U
}
function showType(args: GenericType<number, string>) {
console.log(args)
}
showType({ id: 1, name: "test" })
// Output: {id: 1, name: "test"}
function showTypeTwo(args: GenericType<string, string[]>) {
console.log(args)
}
showTypeTwo({ id: "001", name: ["This", "is", "a", "Test"] })
// Output: {id: "001", name: Array["This", "is", "a", "Test"]}
泛型类型可以接收多个参数。这里,我们传入两个参数:T和U,然后将它们用作属性的类型注释。也就是说,我们现在可以使用接口并提供不同的类型作为参数。
4实用程序类
TypeScript提供了方便的内置工具,帮助您轻松地操作类型。要使用它们,您需要将要转换的类型传递给<>。
部分< T >
Partial允许您使类型T的所有属性都是可选的。它会添加a ?在每个字段旁边标记。
interface PartialType {
id: number
firstName: string
lastName: string
}
function showType(args: Partial<PartialType>) {
console.log(args)
}
showType({ id: 1 })
// Output: {id: 1}
showType({ firstName: "John", lastName: "Doe" })
// Output: {firstName: "John", lastName: "Doe"}
如您所见,我们有一个接口PartialType,它被用作showType()函数接收的参数的类型注释。为了使属性可选,我们必须使用Partial关键字并传入类型PartialType作为参数。也就是说,现在所有字段都是可选的。
5 要求需要< T >
与Partial不同,Required实用程序生成类型T的所有属性。
id: number
firstName?: string
lastName?: string
}
function showType(args: Required<RequiredType>) {
console.log(args)
}
showType({ id: 1, firstName: "John", lastName: "Doe" })
// Output: { id: 1, firstName: "John", lastName: "Doe" }
showType({ id: 1 })
// Error: Type '{ id: number: }' is missing the following properties from type 'Required<RequiredType>': firstName, lastName
Required实用程序将使所有属性都成为必需的,即使我们在使用实用程序之前先将它们设置为可选的。如果省略了某个属性,TypeScript会抛出一个错误。
6 只读的< T >
这个实用程序类型将转换类型T的所有属性,以使它们不能用新值重新分配。
interface ReadonlyType {
id: number
name: string
}
function showType(args: Readonly<ReadonlyType>) {
args.id = 4
console.log(args)
}
showType({ id: 1, name: "Doe" })
// Error: Cannot assign to 'id' because it is a read-only property.
这里,我们使用实用程序Readonly使ReadonlyType的属性不可重新分配。也就是说,如果您试图给这些字段中的一个新值,就会抛出一个错误。
除此之外,您还可以在属性前使用关键字readonly,使其不可重新分配。
interface ReadonlyType {
readonly id: number
name: string
}
7选择< T, K >
它允许您通过选择现有模型T的一些属性K来创建新类型。
interface PickType {
id: number
firstName: string
lastName: string
}
function showType(args: Pick<PickType, "firstName" | "lastName">) {
console.log(args)
}
showType({ firstName: "John", lastName: "Doe" })
// Output: {firstName: "John"}
showType({ id: 3 })
// Error: Object literal may only specify known properties, and 'id' does not exist in type 'Pick<PickType, "firstName" | "lastName">'
Pick与我们已经看到的前面的实用程序有一点不同。它需要两个参数——T是您想要从中选择元素的类型,K是您想要选择的属性。您还可以通过使用管道(|)符号将它们分开来选择多个字段。
8省略< T, K >
省略实用程序与Pick类型相反。它将从类型T中删除K个属性,而不是选择元素。
interface PickType {
id: number
firstName: string
lastName: string
}
function showType(args: Omit<PickType, "firstName" | "lastName">) {
console.log(args)
}
showType({ id: 7 })
// Output: {id: 7}
showType({ firstName: "John" })
// Error: Object literal may only specify known properties, and 'firstName' does not exist in type 'Pick<PickType, "id">'
这个实用程序类似于Pick的工作方式。它期望类型和属性从该类型中省略。
8提取< T U >
Extract允许您通过选择两种不同类型的属性来构造类型。该实用程序将提取从T所有的属性,是分配给U。
interface FirstType {
id: number
firstName: string
lastName: string
}
interface SecondType {
id: number
address: string
city: string
}
type ExtractType = Extract<keyof FirstType, keyof SecondType>
// Output: "id"
在这里,我们有两种类型的共同属性id。因此,通过使用Extract关键字,我们得到字段id,因为它在两个接口中都存在。如果您有多个共享字段,该实用程序将提取所有类似的属性。
9 排除
与Extract不同,Exclude实用程序将通过排除已经存在于两种不同类型中的属性来构造类型。它排除了所有可分配给U的字段。
interface FirstType {
id: number
firstName: string
lastName: string
}
interface SecondType {
id: number
address: string
city: string
}
type ExcludeType = Exclude<keyof FirstType, keyof SecondType>
// Output; "firstName" | "lastName"
正如您在这里看到的,属性firstName和lastName可分配给SecondType类型,因为它们不存在。通过使用Extract关键字,我们将按预期获得这些字段。
10 记录< K, T >
这个实用程序帮助您构造一个具有一组给定类型t的属性K的类型。当需要将一个类型的属性映射到另一个类型时,Record非常方便。
interface EmployeeType {
id: number
fullname: string
role: string
}
let employees: Record<number, EmployeeType> = {
0: { id: 1, fullname: "John Doe", role: "Designer" },
1: { id: 2, fullname: "Ibrahima Fall", role: "Developer" },
2: { id: 3, fullname: "Sara Duckson", role: "Developer" },
}
// 0: { id: 1, fullname: "John Doe", role: "Designer" },
// 1: { id: 2, fullname: "Ibrahima Fall", role: "Developer" },
// 2: { id: 3, fullname: "Sara Duckson", role: "Developer" }
Record的工作方式相对简单。这里,它期望一个数字作为类型,这就是为什么我们将0、1和2作为employees变量的键。如果尝试使用字符串作为属性,则会抛出错误。接下来,属性集由EmployeeType给出,因此对象包含字段id、fullName和role。
11 NonNullable < T >
它允许您从类型T中删除null和undefined。
type NonNullableType = string | number | null | undefined
function showType(args: NonNullable<NonNullableType>) {
console.log(args)
}
showType("test")
// Output: "test"
showType(1)
// Output: 1
showType(null)
// Error: Argument of type 'null' is not assignable to parameter of type 'string | number'.
showType(undefined)
// Error: Argument of type 'undefined' is not assignable to parameter of type 'string | number'.
这里,我们将类型NonNullableType作为参数传递给NonNullable实用程序,该实用程序通过从该类型中排除null和undefined来构造一个新类型。也就是说,如果你传递一个可为空的值,TypeScript会抛出一个错误。
顺便说一下,如果你在tsconfig文件中添加——strictNullChecks标志,TypeScript会应用非空性规则。
12 映射类型
映射类型允许您获取一个现有的模型,并将其每个属性转换为一个新类型。注意,前面介绍的一些实用程序类型也是映射类型。
type StringMap<T> = {
[P in keyof T]: string
}
function showType(arg: StringMap<{ id: number; name: string }>) {
console.log(arg)
}
showType({ id: 1, name: "Test" })
// Error: Type 'number' is not assignable to type 'string'.
showType({ id: "testId", name: "This is a Test" })
// Output: {id: "testId", name: "This is a Test"}
StringMap<>将把传入的任何类型转换为字符串。也就是说,如果我们在函数showType()中使用它,接收到的参数必须是一个字符串——否则,TypeScript将抛出一个错误。
13 类型警卫 类型保护允许您使用操作符检查变量或对象的类型。它是一个条件块,使用typeof、instanceof或in返回类型
typeof
function showType(x: number | string) {
if (typeof x === "number") {
return `The result is ${x + x}`
}
throw new Error(`This operation can't be done on a ${typeof x}`)
}
showType("I'm not a number")
// Error: This operation can't be done on a string
showType(7)
// Output: The result is 14
如您所见,我们有一个普通的JavaScript条件块,它检查typeof接收到的参数的类型。有了这些之后,您现在可以用这个条件来保护您的类型。
instanceof
class Foo {
bar() {
return "Hello World"
}
}
class Bar {
baz = "123"
}
function showType(arg: Foo | Bar) {
if (arg instanceof Foo) {
console.log(arg.bar())
return arg.bar()
}
throw new Error("The type is not supported")
}
showType(new Foo())
// Output: Hello World
showType(new Bar())
// Error: The type is not supported
与前面的示例一样,这个示例也是一个类型保护,它检查接收到的参数是否是Foo类的一部分,然后对其进行处理。
in
interface FirstType {
x: number
}
interface SecondType {
y: string
}
function showType(arg: FirstType | SecondType) {
if ("x" in arg) {
console.log(`The property ${arg.x} exists`)
return `The property ${arg.x} exists`
}
throw new Error("This type is not expected")
}
showType({ x: 7 })
// Output: The property 7 exists
showType({ y: "ccc" })
// Error: This type is not expected
in操作符允许您检查作为参数接收的对象上是否存在属性x。
14 有条件的类型 它测试两种类型,并根据测试结果选择其中一种。
type NonNullable<T> = T extends null | undefined ? never : T
这个非空实用程序类型的例子检查类型是否为空,并根据它来处理。正如您所注意到的,它使用JavaScript三元操作符。