繁体   English   中英

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

[英]How to get Type of Array in Typescript generics

我有一个这样的方法:

public select(fieldName: keyof TType)

其中TType可以是数组类型。 在数组类型的情况下, fieldName将正确地为我提供Array类型的所有属性名称。

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

有没有办法做到这一点?

额外问题:有没有办法限制 TType 为数组类型?

您绝对可以创建一个条件类型函数,将数组类型解包至一层深度,然后对结果使用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

请注意,我在这里完全取消了条件类型,因为它更直接。


希望有所帮助; 祝你好运!

您将需要一个小助手来提取盒装类型:

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')

可以通过按数字索引来从类型type U = T[]的数组中确定类型参数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

为什么要使用运算符keyof 在每种情况下都会导致一个数组,因为 fieldName 将只是TType类型中的键。

如果你想要一个User数组,你需要这样定义TType

type TType = User[]
...
public select(fieldName: TType) {
   ...
}

如果你希望TType是任何数组,你将把它定义为这样的类型 TType = any[]

但是在第二个定义中,打字稿将无法推断内部类型(在这种情况下,我认为User不是您想要的类型。

最后,如果TType可以是多种类型的数组:type TType = User[] | 随便[] | ...

如果您想要更详细的答案,请对您想要的内容提供更好的解释。
与此同时,我希望这会有所帮助;)
塞伯

使用TType[0]作为类型在实践中对我TType[0] 所以,在你的例子中:

public select(fieldName: keyof TType[0])

尽管它很丑,但它似乎有效!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM