我尝试代码:
nth(['a', 'b'], 1) // function nth<string[], 1>(o: string[], k: 1): string
nth<['a', 'b']>(['a', 'b'], 1) // function nth<["a", "b"], number | "0" | "1" | "length" | "toString" | "toLocaleString" | "pop" | "push" | "concat" | "join" | "reverse" | "shift" | "slice" | "sort" | "splice" | "unshift" | "indexOf" | ... 14 more ... | "values">(o: [...], k: number | ... 30 more ... | "values"): "a" | ... 29 more ... | (() => IterableIterator<...>)
nth<['a', 'b'], 1>(['a', 'b'], 1) // function nth<["a", "b"], 1>(o: ["a", "b"], k: 1): "b"
function nth<O, K extends keyof O>(o: O, k: K): O[K] {
return o[k]
}
nth<['a', 'b'], 1>(...)
效果很好,但有什么办法,使nth(...)
按预期工作?
我相信这里的问题是,['a', 'b']
实际上是由打字稿类型为string[]
,所以访问一个数组中的元素会给你string
。从概念上讲,你是想['a', 'b']
被类型化为一个元组。例如:
const array = ['a', 'b']
const str = array[1] // this is typed as string
const tuple: ['a', 'b'] = ['a', 'b']
const b = tuple[1] // this is typed as 'b'
打字稿不会自动推断数组常量元组的,可能会导致一些问题 - 看this issue的多一点背景。
在你的情况,你通过期望它应该工作:
nth(['a', 'b'] as ['a', 'b'], 1)
// or
const value: ['a', 'b'] = ['a', 'b']
nth(value, 1)
我建议为nth
创建泛型类型并将其应用在功能类型定义。例:
type Nth<A extends any[], I extends number> = A[I];
type R = Nth<[1, 2, 3], 1>
function nth<A extends any[], I extends number>(o: A, k: I): Nth<A, I> {
return o[k]
}
let result = nth(['a', 'b'], 1)
let result1 = nth<['a', 'b'], 1>(['a', 'b'], 1)
let result2 = nth<['a', 'b'], 1>(['a', 'b'], 1);
这是您所期望的行为?
---编辑---
如果你想获得“B”,而不是字符串,你可以这样做:
type Nth<A extends string[], I extends number> = A[I];
let result = nth(['a', 'b'], 1) // string
let result = nth(['a', 'b'] as ['a', 'b'], 1) // string
let result1 = nth<['a', 'b'], 1>(['a', 'b'], 1) // 'b'
let result2 = nth<['a', 'b'], 1>(['a', 'b'], 1); // 'b'