如何为“类型”创建“新”构造函数

问题描述 投票:0回答:1

有没有办法为一个

type
创建一个构造函数,它别名为一个本地对象?

我目前有一个定义的类型,应该用默认值构造。它将在很多地方创建,所以我想确保它的创建是一致的。

export enum Category { a='a', e='e', i='i', o='o', u='u' };

export type CategorisedItems = { [category in Category]: string[] };

export function createCategorisedItems(): CategorisedItems {
  return Object.assign({}, ...Object.values(Category).map(category => ({[category]: []})));
}
// {
//   a: [],
//   e: [],
//   i: [],
//   o: [],
//   u: []
// }

我可以在其他对象中创建它:

import { CategorisedItems, createCategorisedItems } from './categories';

export class PendingData {
  public readonly categorisedItems: CategorisedItems = createCategorisedItems();
}

但我希望能够改用

new
语法。

import { CategorisedItems } from './categories';

export class PendingData {
  public readonly categorisedItems: CategorisedItems = new CategorisedItems();
}

这可能还是一厢情愿?

typescript constructor prototype type-alias
1个回答
2
投票

小心枚举,检查它们转换成什么:

var Category;
(function (Category) {
    Category[Category["a"] = 0] = "a";
    Category[Category["e"] = 1] = "e";
    Category[Category["i"] = 2] = "i";
    Category[Category["o"] = 3] = "o";
    Category[Category["u"] = 4] = "u";
})(Category || (Category = {}));

// or short:
var Category = {0: 'a', 1: 'e', 2: 'i', 3: 'o', 4: 'u', a: 0, e: 1, i: 2, o: 3, u: 4}

我会使用联合类型:

// the materialized keys (types don't exist at runtime).
const categoryKeys = ["a", "e", "i", "o", "u"] as const;
// and something for the typing
export type Category = typeof categoryKeys[number]; 
// => type Category = "a" | "e" | "i" | "o" | "u"

对于您的主要问题,如何将

createCategorisedItems()
变成一个班级。基本上,我们想要的是:

class CategorisedItems {
    [category in Category]: string[];

    constructor() {
        for (const key of categoryKeys) {
            this[key] = [];
        }
    }
}

但是当用映射属性声明类时,TS 一方面唠叨说属性可能没有实现,但它不让我实现它们,因为它们没有定义......:(

JS 和一些演员来拯救:

const categoryKeys = ["a", "e", "i", "o", "u"] as const;

export type Category = typeof categoryKeys[number];

export type CategorisedItems = { [category in Category]: string[]; }

// a good ol JS constructor function, ...
export const CategorisedItems = function (this: CategorisedItems) {
    if (!new.target) {
        throw new Error(`Constructor CategorisedItems cannot be invoked without 'new'`);
    }

    for (const key of categoryKeys) {
        this[key] = [];
    }
    // ... but we need to nudge TS into the right direction.
} as unknown as new () => CategorisedItems

以及指向 TS Playground

的链接

学习起来很酷。这样做的副作用是我不能再将 CategorisedItems 用作 PendingData 类或其他任何地方的类型。 “‘CategorisedItems’指的是一个值,但在这里被用作一种类型。你是说‘typeof CategorisedItems’吗?”

我忘了

export type CategorisedItems = ...;
应该解决这个问题。

或者您可以将其隐藏为导出的派生类背后的实现细节:

const categoryKeys = ["a", "e", "i", "o", "u"] as const;

export type Category = typeof categoryKeys[number];

type CategorisedItemsBase = { [category in Category]: string[]; }

const CategorisedItemsBase = function (this: CategorisedItemsBase) {
    for (const key of categoryKeys) {
        this[key] = [];
    }
} as unknown as new () => CategorisedItemsBase

// and then:
export class CategorisedItems extends CategorisedItemsBase { }

这也使得构建其唯一目的是实例化映射属性的基本函数变得更简单;你可以回到更好的

class
语法,而不必做
CategorisedItemsBase.prototype.xyz = ...

© www.soinside.com 2019 - 2024. All rights reserved.