TypeScript细碎知识点:T[number]、T['length'] 与 as const

🐹 一、T[number]、T['length']

T[number] 用来获取元组的元素类型联合
T['length'] 用来获取元组的元素类型个数
💡元组类型是另一种Array类型,它确切地知道它包含多少元素,以及在特定位置包含哪些类型。
type A = ['a', 'b', 'c']

type C = A['length'] // 3
type B = A[number]   // "a" | "b" | "c"

对于数组来说

type A = boolean[]

type C = A['length'] // number
type B = A[number]   // boolean

🤔:这里估计会有一个疑问,为什么数组这里的T['length']得到的是number, 而元祖中得到的却是‘3’

数组:TypeScript 将数组视为一个可以动态增长或缩小的集合,因此 length 属性的类型是 number。
元组:TypeScript 将元组视为一个固定长度的集合,每个位置的类型和数量都是已知的,因此 length 属性的类型是一个具体的数字。

示例一:第一个元素

题目:实现一个通用First<T>,它接受一个数组T并返回它的第一个元素的类型。

type arr1 = ['a', 'b', 'c']
type arr2 = [3, 2, 1]

type head1 = First<arr1> // expected to be 'a'
type head2 = First<arr2> // expected to be 3

结果

type First<T> = T extends any[] ? T[0] : never

示例二: 最后一个元素

题目:实现一个通用Last<T>,它接受一个数组 T 并返回其最后一个元素的类型。

type arr1 = ['a', 'b', 'c', 'd']
type arr2 = [3, 2, 1]

type tail1 = Last<arr1> // expected to be 'c'
type tail2 = Last<arr2> // expected to be 1

结果

type Last<T> = T extends any[] ? [any,...T][T['length']] : never

示例三:出堆

题目:实现一个通用Pop<T>,它接受一个数组 T 并返回一个没有最后一个元素的数组。

type arr1 = ['a', 'b', 'c', 'd']
type arr2 = [3, 2, 1]

type re1 = Pop<arr1> // expected to be ['a', 'b', 'c']
type re2 = Pop<arr2> // expected to be [3, 2]

结果:

type Pop<T extends any[]> = T extends [...infer U, infer P] ? U : never

🐹 二、as const

as const 是 TypeScript 中的一个用于修饰符,它可以被用来修改类型推断的行为。

🍀 当 as const 修饰符用在变量声明或表达式的类型上时,它会强制 TypeScript 将变量或表达式的类型视为不可变的(immutable)。这意味着,如果你尝试对变量或表达式进行修改,TypeScript 会报错。例如:

const foo = ['a', 'b'] as const;
foo.push('c');  // TypeScript 会报错,因为 foo 类型被声明为不可变的

const bar = { x: 1, y: 2 } as const;
bar.x = 3;  // TypeScript 会报错,因为 bar 类型被声明为不可变的

🍀 as const 修饰符还可以用来修改对象字面量和数组字面量的类型推断。在这种情况下,as const 会强制 TypeScript 将对象字面量或数组字面量的类型推断为不可变的,即使没有显式地指定类型。例如:

const foo = ['a', 'b'] as const;  // 等价于 const foo: ['a', 'b'] = ['a', 'b']
const bar = { x: 1, y: 2 } as const;  // 等价于 const bar: { x: 1, y: 2 } = { x: 1, y: 2 }

在这两个例子中,TypeScript 会将 foobar 的类型推断为不可变的数组和对象,即使没有显式地指定类型。

😊 总结一下就是,当使用 const assert 时,ts做了以下几件事

  1. 该表达式中的任何文字类型都不应该被扩展(例如,不应该从“hello”变成字符串)

    let a = 'hello' as const  //等价于 let a: 'hello' = 'hello'
  2. 对象字面值获得只读属性

    const bar = { x: 1, y: 2 } as const;  // 等价于 const bar: { x: 1, y: 2 } = { x: 1, y: 2 }
  3. 数组字面值变成只读元组

    const foo = ['a', 'b'] as const;  // 等价于 const foo: ['a', 'b'] = ['a', 'b'] 

posted on 2024-11-18 15:13  梁飞宇  阅读(146)  评论(0)    收藏  举报