【问题标题】:Specialized function signatures in TypeScriptTypeScript 中的专用函数签名
【发布时间】:2020-05-10 12:21:32
【问题描述】:

我正在使用 TypeScript 中的专用函数签名。我的理解是以下应该有效:

// Basic superclass and subclass
class Model { }
class Product extends Model { name: string; }

// Define interface for singleton factory class with generic create method.
interface IModels { create(type: any): Model; }

const ctors = {product: Product};

// Implement generic version of create.
class Models implements IModels {
  create(type: any): Model { return new ctors[type](); }
}

// Extend interface with specialized signature.
interface IModels { create(type: "product"): Product; }

const models = new Models;

const product: Product = models.create("product");

但是,这会在最后一行产生以下错误:

Class 'Models' incorrectly implements interface 'IModels'.
  Types of property 'create' are incompatible.
    Type '(type: any) => Model' is not assignable to type '{ (type: any): Model; (type: "product"): Product; }'.
      Type 'Model' is not assignable to type 'Product'.
        Property 'name' is missing in type 'Model'.

如果我将create 的返回类型从Model 更改为any,那么它会编译,但为什么我必须这样做?

【问题讨论】:

    标签: typescript


    【解决方案1】:

    界面...

    interface IModels { create(type: "product"): Product; }
    

    ...通过方法签名在您的Models 类中实现...

    create(type: any): Model;
    

    ...因为any"product" 的可接受实现。然后编译器只使用来自Models 类的方法信息。

    您还可以通过将此信息添加到 Models 类以及重载签名中来消除错误:

    class Models implements IModels {
        create(type: "product"): Product;
        create(type: any): Model;
        create(type: any): Model {
            return new ctors[type]();
        }
    }
    

    2020 年更新

    现在,您很可能会按照以下思路写一些东西:

    const ctors = { product: Product };
    
    class Models {
      create(type: keyof typeof ctors): Model {
        return new ctors[type]();
      }
    }
    

    【讨论】:

    • 这不是我对它应该如何工作的理解。带有特定类型值的附加声明明确表示,当使用'product' 类型调用函数时,它返回Product 类型的值。 TS docs 给出了 interface Document {createElement(tagName: "div"): HTMLDivElement; 的例子,它告诉 TS 当 document.createElement 被调用时带有 "div" 的参数,那么返回值是 HTMLDivElement,所以一切正常。
    • @torazaburo 抱歉,没有注意到第二个界面。我更新了我的答案。
    • create(type: any): Model;(第 3 行)在 TypeScript 3.8.3 中是多余的。
    • @SlavenSemper 这似乎仍然是必要的。当我删除它时,只有一个签名可供选择。也就是说,现在结合使用区分联合和索引类型可能会更好。这两个都可以阅读here
    • @SlavenSemper 这取决于他们是否要传入一个键入为 any 的值。确实很可能他们没有,但是如果有人删除了第 3 行,那么他们也可以删除第 2 行。无论如何,我用另一个现在有人可能会做的例子更新了答案。
    猜你喜欢
    • 2020-09-19
    • 1970-01-01
    • 1970-01-01
    • 2018-09-14
    • 2018-07-18
    • 1970-01-01
    • 2020-12-24
    • 1970-01-01
    • 2019-04-20
    相关资源
    最近更新 更多