const arr = [1, 2, 3] // `arr` type is `number[]`
const x = arr[0] // `x` type is `number | undefined`
const y = arr[1000] // `y` type is `number | undefined`
const x: [number, number, number] = [1, 2, 3]
const x = arr[0] // `x` type is `number`
const y = arr[1000] // error: Tuple type '[number, number, number]' of length '3' has no element at index '9'.
当索引溢出时, 直接编译报错
第二种方法是使用 const assertions, 即断言成字面量类型:
const arr = [1, 2, 3] as const // `arr` type is `readonly [1, 2, 3]`
const x = arr[0] // `x` type is `number`
const y = arr[1000] // error: Tuple type '[number, number, number]' of length '3' has no element at index '9'.
noUncheckedIndexedAccess
其实没啥聊的, 这个配置属于 4.1 版本的一个新 feature, 该属性的作用在于使用索引访问某类型属性时, 该类型属性会被加上
undefined
类型:举个例子: 在没有该配置的情况下, 访问一个普通的 array 的类型如下:
实际上这样的类型是不特别准确的, 由于
arr
这个数组长度没有限制, ts 没有足够的信息去判断其元素到底有多少个, 因此即使索引超过初始化定义的长度, ts 还是认为该元素"存在"noUncheckedIndexedAccess
这一配置能够在使用索引访问时, 添加undefined
类型:可以看到开启配置之后, 任何索引的访问都会带上
undefined
类型, 毕竟 ts 此时也不确定 arr 具体的形状是啥样了, 甚至是一个空 array 都是有可能的.Tuple & const assertions
那如何定义固定长度的 array 类型呢? 一种方法是定义为 Tuple 类型:
当索引溢出时, 直接编译报错
第二种方法是使用 const assertions, 即断言成字面量类型:
使用这种类型断言之后, 类型会自动加上
readonly
关键字, ts 编译器就知道这种数据类型是immutable
的, 自然长度也不会变了以上两种方法不管
noUncheckedIndexedAccess
有没有配置, 都能正确识别索引溢出的错误自定义类型
然而有一种情况下识别出的元素类型还是存在
undefined
类型的.这里保持
noUncheckedIndexedAccess
配置开启, 有以下代码:我们仍旧使用
Tuple
类型声明数组, 并且严格规定其元素. 但访问的索引给定一个比较宽泛的类型number
, 这时候去拿数组里的元素时发现他的类型又给出了undefined
类型真实的场景会有, 当使用
map()
,forEach()
这些方法时, 可能会有(其实并没有)如下代码:这时候
v
类型是1 | 2 | 3
, 但是我自己用索引拿到的元素b
类型却是1 | 2 | 3 | undefined
, 有点困惑...我想 ts 编译器应该也困惑吧, 毕竟索引类型是
number
了, 它也不知道具体是哪个索引, 所以我只能又给一个undefined
, 虽然我数组的类型是严格的Tuple
所以这里的索引
i
需要更加准确, 如果手动给的话, 即为0 | 1 | 2
. 但是该如何根据已知的数组a
和它的类型A
自动推断出对应的索引类型呢?比较通用并且容易想到的一种做法是用
keyof
:虽然最后的结果类型是
string
, 但是对于索引已经够用了IndexOf
另一种做法就是自定义一个类型, 这里叫
IndexOf
, 该类型接受一个类型参数, 即数组的类型, 返回值是该数组的索引类型, 这里先看实现:使用就非常简单了
最后得到的类型顺序不重要(我觉得...)
简单讲一下过程:
T
和S
是两个泛型参数,T
的形状是一个 array,S
类型为数字数组, 默认为一个空数组类型. 这个S
存放了每次递归的状态, 这里后面会讲?
前的extends
语句, 这个语句是递归的终止条件, 满足条件为当T
的长度和S
的长度一样?
后的第一条语句, 这条语句为返回结果, 返回的是S[number]
, 也就是对S
取里面所有元素的 union 的值S
自增, 从一开始的[]
, 一直到每次递增添加一个数字, 所以最后的S
值为[0, 1, 2]
最后发现了一个可以做类型体操的地方: type-challenges
参考