如何在Typescript泛型中获取数组类型

时间:2018-12-14 15:36:12

标签: typescript

我有一个这样的方法:

public select(fieldName: keyof TType)

TType可以是数组类型。如果是数组类型,fieldName将为我正确提供类型为Array的所有属性名称。

如果我用User[]类型调用此方法,我想获得User的属性而不是Array的属性。

有什么方法可以做到吗?

额外的问题:有什么方法可以将TType限制为数组类型?

5 个答案:

答案 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]

虽然丑陋,但似乎可行!