【问题标题】:How to create a type excluding instance methods from a class in typescript?如何从打字稿中的类中创建不包括实例方法的类型?
【发布时间】:2019-08-24 01:37:44
【问题描述】:

给定一个包含属性和方法的类,我想派生一个只包含其属性的类型。

例如,如果我定义一个类如下:

class MyObject {

  constructor(public prop1: string, public prop2: number) {}

  instanceMethod() { ... }
}

我想要一个类型,比如MyObjectConstructor,它会是这样的:

type MyObjectConstructor = {
  prop1: string;
  prop2: number;
}

我知道我可以使用内置类型Pick 并通过名称手动选择我想要的键,但我不想重复所有键,并且每次添加时都必须更改它们我的班级的新属性。

有没有办法定义一个泛型类型ConstructorType<T>只返回打字稿中类的属性?

【问题讨论】:

  • 您基本上想要的是函数参数和对象之间的某种形式的转换,其中键是参数名称,值是参数类型。我不想这么说,但没有直接解决您的问题的方法。你找到的所有东西都会感觉像是“黑客”

标签: typescript typescript-generics


【解决方案1】:

感谢这篇文章,我找到了一种方法来排除与给定类型匹配的所有属性:https://medium.com/dailyjs/typescript-create-a-condition-based-subset-types-9d902cea5b8c

我做了一些改编,但这里是细节:

// 1 Transform the type to flag all the undesired keys as 'never'
type FlagExcludedType<Base, Type> = { [Key in keyof Base]: Base[Key] extends Type ? never : Key };
    
// 2 Get the keys that are not flagged as 'never'
type AllowedNames<Base, Type> = FlagExcludedType<Base, Type>[keyof Base];
    
// 3 Use this with a simple Pick to get the right interface, excluding the undesired type
type OmitType<Base, Type> = Pick<Base, AllowedNames<Base, Type>>;
    
// 4 Exclude the Function type to only get properties
type ConstructorType<T> = OmitType<T, Function>;

Try It

可能有更简单的方法,我尝试使用ConstructorParameters 并定义构造函数签名但没有结果。

更新

在此处浏览 typescript 文档时发现了一个等价物: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types

type NonFunctionPropertyNames<T> = {
  [K in keyof T]: T[K] extends Function ? never : K;
}[keyof T];
type NonFunctionProperties<T> = Pick<T, NonFunctionPropertyNames<T>>;

由于省略的类型不是通用的,所以它有点不那么冗长,但它的想法是一样的。

【讨论】:

  • 虽然比其他建议的答案更冗长,但这似乎对我有用,谢谢! gist.github.com/raould/645c93035adfd479b1801d2c539ee55e
  • 这个答案的问题是认为它排除了方法,它也排除了函数属性,这是有问题的。不幸的是,Typescript 目前似乎没有提供区分方法和函数属性的方法,尽管 VSCode 悬停提示实际上可以区分它们。
【解决方案2】:

给定一个包含属性和方法的类,我想派生一个只包含其属性的类型。

从您的示例中,您似乎希望结果仅包含字段 (as opposed to only properties)。这是一种从对象或类实例中挑选出字段的类型。

type DataPropertyNames<T> = {
  [K in keyof T]: T[K] extends Function ? never : K;
}[keyof T];

type DataPropertiesOnly<T> = {
  [P in DataPropertyNames<T>]: T[P] extends object ? DTO<T[P]> : T[P]
};

export type DTO<T> = DataPropertiesOnly<T>;

我使用首字母缩略词DTO 来表示数据传输对象。感谢 l00ser2410656 的this playground demo

【讨论】:

  • 我希望这对我有用 :-) 感谢您的发帖。目前,当我尝试它时,它以一个空类型结束。 gist.github.com/raould/f523e235751f26a83c72154dde298bc6
  • @l00ser2410656 不错的收获。您注意到的是每个属性都是可选的,而不是类型为空。我已更改答案以从类型定义中删除可选属性标记 ?。它现在将按照您的预期工作。
  • 似乎这不适用于Partial&lt;DTO&lt;T&gt;&gt;DTO&lt;Partial&lt;T&gt;&gt; ?
  • @DrSensor “不起作用”是什么意思。这是一个使用Partial&lt;DTO&lt;T&gt;&gt; 的示例:typescriptlang.org/play?#code/…
【解决方案3】:

在阅读此issue 时,我发现有人在发布这种简洁的类型

type ExcludeMethods<T> = 
  Pick<T, { [K in keyof T]: T[K] extends (_: any) => any ? never : K }[keyof T]>;

请注意,此类型不会删除 getter 和 setter。

编辑:甚至更短

type ExcludeMethods<T> = 
  Pick<T, { [K in keyof T]: T[K] extends Function ? never : K }[keyof T]>;

【讨论】:

    【解决方案4】:
    export type DTO<T> = {
        [P in {
            [K in keyof T]: undefined extends T[K] ? never : T[K] extends (...args) => any ? never : K;
        }[keyof T]]: T[P] extends object ? DTO<T[P]> : T[P];
    } &
        Partial<
            {
                [P in {
                    [K in keyof T]: undefined extends T[K] ? K : never;
                }[keyof T]]: T[P] extends object ? DTO<T[P]> : T[P];
            }
        >;
    

    【讨论】:

    • 您好,欢迎来到 Stack Overflow,尝试在您的代码中附上对代码的解释。
    • 看到这个我就头疼。描述会很有趣。否则这不应该是最好的结果
    • 这很有趣。 undefined extends T[K} 的目的是什么?
    • @DrSensor 我相信它可以处理密钥是可选的情况,否则打字稿会抱怨Type 'undefined' is not assignable to type 'keyof T' 例如class Container { optional?: string }
    【解决方案5】:
    export type Defined<T> = Exclude<T, undefined>;
            
    export type NonFunctionPropertyNames<T> = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T];
        
    export type PartialModel<T extends Model> = {
      [K in NonFunctionPropertyNames<T>]?: Defined<T[K]>
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-22
      • 1970-01-01
      • 1970-01-01
      • 2017-07-02
      • 1970-01-01
      • 2020-11-03
      • 2021-12-31
      • 2012-11-07
      相关资源
      最近更新 更多