Joh*_*ohn 4 typescript typescript-generics
我有一个泛型类,其中类型参数是一个元组。我在类上创建一个方法时遇到问题,该方法的参数仅限于元组的索引。
例如(游乐场链接):
class FormArray<T extends [any, ...any[]]> {
constructor(public value: T) {}
// how to restrict `I` to only valid index numbers of `T` ?
get<I extends keyof T>(index: I): T[I] {
return this.value[index];
}
}
Run Code Online (Sandbox Code Playgroud)
我知道您可以做的是keyof获取元组上的所有属性,其中包括与元组包含的对象关联的键(即“0”、“1”等)。不幸的是,keyof会拉入元组的所有属性,包括“长度”、“拼接”等。
我尝试使用keyof并排除所有不属于 type 的属性number,但后来我意识到索引属性(“0”、“1”等)是由keyofas type返回的string。
目前可以在 TypeScript 中完成此任务吗?
您可以排除keyof any[]并keyof T仅保留适当的元组键,不幸的是它们将采用字符串形式:
class FormArray<T extends [any, ...any[]]> {
constructor(public value: T) {}
get<I extends Exclude<keyof T, keyof any[]>>(index: I): T[I] {
return this.value[index];
}
}
new FormArray([1,2, 3]).get("0");
Run Code Online (Sandbox Code Playgroud)
您还可以添加到数字的映射,但恐怕这必须是手动操作:
interface IndexMap {
0: "0"
1: "1"
2: "2"
3: "3"
4: "4"
/// add up to a resonable number
}
type NumberArrayKeys<T extends PropertyKey> = {
[P in keyof IndexMap]: IndexMap[P] extends T ? P : never
}[keyof IndexMap]
class FormArray<T extends [any, ...any[]]> {
constructor(public value: T) { }
// how to restrict I to only valid index numbers of T ?
get<I extends Exclude<keyof T, keyof any[]> | NumberArrayKeys<keyof T>>(index: I): T[I] {
return this.value[index];
}
}
let a = new FormArray([1, "2", 3]).get("0");
let b = new FormArray([1, "2", 3]).get("1");
let c = new FormArray([1, 2, 3]).get(0); // number
let d = new FormArray([1, "2", 3]).get(1); // string
Run Code Online (Sandbox Code Playgroud)
请注意,我很惊讶T[I]即使I是 a number即使keyof T返回索引为stringnotnumber
这种认识使我想到了另一种可能的解决方案,其中I也可以是number. 如果数字在元组长度范围内,它将返回适当的类型,否则将返回undefined。这不会是调用时的错误,但由于返回值将被键入,就好像undefined您使用strictNullChecks它一样,因此您几乎无法对其执行任何操作:
class FormArray<T extends [any, ...any[]]> {
constructor(public value: T) { }
// how to restrict I to only valid index numbers of T ?
get<I extends Exclude<keyof T, keyof any[]> | number>(index: I): T[I] {
return this.value[index];
}
}
let a = new FormArray([1, "2", 3]).get("0");
let b = new FormArray([1, "2", 3]).get("1");
let c = new FormArray([1, 2, 3]).get(0); // number
let d = new FormArray([1, "2", 3]).get(1); // string
let e = new FormArray([1, "2", 3]).get(10); // undefined
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
399 次 |
| 最近记录: |