我有一个这样的方法:
public select(fieldName: keyof TType)
TType
可以是数组类型。如果是数组类型,fieldName
将为我正确提供类型为Array
的所有属性名称。
如果我用User[]
类型调用此方法,我想获得User
的属性而不是Array
的属性。
有什么方法可以做到吗?
额外的问题:有什么方法可以将TType限制为数组类型?
答案 0 :(得分:2)
您绝对可以创建一个conditional类型的函数,该函数可以将数组类型解包到最深一层,然后在结果上使用keyof
。例如:
// unwrap up to one level
type Unarray<T> = T extends Array<infer U> ? U : T;
// your class maybe
declare class Thingy<T> {
constructor(t: T);
public select(fieldName: keyof Unarray<T>): void;
}
// your interface maybe
interface User {
name: string,
age: number
}
declare const u1: User;
declare const u2: User;
const x = new Thingy(u1);
x.select("name"); // okay
const y = new Thingy([u1, u2]);
y.select("age"); // okay
y.select("push"); // error
我认为这应该可以根据您的需要进行输入。显然,您还需要一个有效的实现(请注意,实现中的条件类型通常需要某种类型断言或重载才能使编译器满意……但您似乎在询问类型而不是实现)。
对于您的其他问题,是的,您可以将T
限制为仅数组类型,如下所示:
// your class maybe
declare class Thingy<T extends Array<any>> {
constructor(t: T);
public select(fieldName: keyof (T[number])): void;
}
// your interface maybe
interface User {
name: string,
age: number
}
declare const u1: User;
declare const u2: User;
const x = new Thingy(u1); // error
const y = new Thingy([u1, u2]);
y.select("age"); // okay
请注意,在这里我完全取消了条件类型,因为它更直接。
希望有所帮助;祝你好运!
答案 1 :(得分:1)
您将需要一些帮助程序来提取盒装类型:
type Unboxed<T> =
T extends (infer U)[]
? U
: T;
然后您的方法如下所示:
interface User {
id: symbol;
name: string;
}
class Foo {
select(fieldName: keyof Unboxed<User[]>) {
console.log(fieldName) // "id" | "name"
}
}
关于您的其他问题:是的,有可能,但可能会感到有些奇怪。
class Foo {
select<T extends any[]>(fieldName: keyof Unboxed<T>) {
console.log(fieldName)
}
}
new Foo()
.select<Window[]>('addEventListener')
类型参数用于描述方法内部的参数或类的通用类型。所以也许您想执行以下操作:
class Foo<T extends any[]> {
select(fieldName: keyof Unboxed<T>) {
console.log(fieldName)
}
}
new Foo<Window[]>()
.select('addEventListener')
答案 2 :(得分:1)
通过按数字索引,例如T
,可以从类型type U = T[]
的数组中确定类型参数U[number]
。
type Foo = {"foo": string};
type Bar = {"bar": number};
type FooArray = Foo[];
type BarArray = Bar[];
FooArray[number]; // {"foo": string}
BarArray[number]; // {"bar": number}
在上面的示例中为TypeScript Playground。
答案 3 :(得分:0)
为什么要使用运算符keyof
?每种情况下都会导致一个数组,因为fieldName仅是TType
类型的键。
如果要使用User
的数组,则需要这样定义TType
:
type TType = User[]
...
public select(fieldName: TType) {
...
}
如果您希望TType
是任何数组,则将其定义为
输入TType = any []
但是在第二种定义中,打字稿将无法推断内部类型(在这种情况下,User
这不是我想要的。
最后,如果TType
可以是多种类型的数组:
类型TType = User [] |随便[] | ...
如果您想获得更详细的答案,请提供所需信息的更好说明。
同时,我希望这会有所帮助;)
塞巴
答案 4 :(得分:0)
在实践中,使用<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="Library">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="Book"/>
</xs:sequence>
</xs:complexType>
<!-- Primary Key -->
<xs:key name="PK">
<xs:selector xpath="Book"/>
<xs:field xpath="."/>
</xs:key>
</xs:element>
<xs:element name="Book" type="xs:string"/>
</xs:schema>
作为类型对我有用。因此,在您的示例中:
TType[0]
虽然丑陋,但似乎可行!