TypeScript:选择具有已定义类型的属性

时间:2017-10-05 10:51:06

标签: typescript

是否可以构造一个TypeScript类型,它只会选择那些类型为X的属性?

interface IA {
    a: string;
    b: number;
}

interface IB extends IA {
    c: number | string;
}

type IAStrings = PickByType<IA, string>;
// IAStrings = { a: string; }
type IBStrings = PickByType<IB, string>;
// IBStrings = { a: string; }
type IBStringsAndNumbers = PickByType<IB, string | number>;
// IBStringsAndNumbers = { a: string; b: number; c: number | string; }

2 个答案:

答案 0 :(得分:6)

是的,这是可能的。我也遇到了这个问题,也在寻找答案,但最终我想通了。

TL; DR

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    // Whenever there's a reusable cell available, dequeue will return it
    let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier") ??
        UITableViewCell(style: .subtitle, reuseIdentifier: "cellIdentifier")

更长的解释版本

/**
 * Returns an interface stripped of all keys that don't resolve to U, defaulting 
 * to a non-strict comparison of T[key] extends U. Setting B to true performs
 * a strict type comparison of T[key] extends U & U extends T[key]
 */
type KeysOfType<T, U, B = false> = {
  [P in keyof T]: B extends true 
    ? T[P] extends U 
      ? (U extends T[P] 
        ? P 
        : never)
      : never
    : T[P] extends U 
      ? P 
      : never;
}[keyof T];

type PickByType<T, U, B = false> = Pick<T, KeysOfType<T, U, B>>;

因此,class c1 { a: number; b: string; c: Date; d?: Date; }; type t1 = keyof c1; // 'a' | 'b' | 'c' | 'd' type t2 = Pick<c1, t1>; // { a: number; b: string; c: Date; d?: Date; } type KeysOfType0<T, U> = { [P in keyof T]: T[P] extends U ? P : never; }; type t3 = KeysOfType0<c1, Date>; // { a: never; b: never; c: "c"; d?: "d"; } // Based on https://github.com/microsoft/TypeScript/issues/16350#issuecomment-397374468 type KeysOfType<T, U> = { [P in keyof T]: T[P] extends U ? P : never; }[keyof T]; type t4 = KeysOfType<c1, Date>; // "c" | "d" type t5 = Pick<c1, t4>; // { c: Date; d?: Date; } type PickByType<T, U> = Pick<T, KeysOfType<T, U>>; type t6 = PickByType<c1, Date>; // { c: Date; d?: Date; } 可以准确给出您在注释中得到的结果。


编辑

如果需要严格类型的实用程序,则需要验证扩展是双向的。下面是一个示例示例,其中原始的KeysOfType实用程序可能返回意外结果,并且提供了两种解决方案。

typescript playground上尝试一下。

PickByType

答案 1 :(得分:0)

将来可以使用enhancements to Mapped Types来完成此操作。

在那之前,你可以分解你的界面,虽然我只推荐它,如果它有意义:

interface IA {
    a: string;
}

interface IA2 extends IA {
    b: number;
}

interface IB extends IA2 {
    c: number | string;
}

这会为您提供您尝试计算的IA类型。

如果这没有意义,那就是手动创建IAStrings界面的情况,该界面只包含您希望它拥有的属性。