有没有办法为一个
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();
}
这可能还是一厢情愿?
小心枚举,检查它们转换成什么:
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 = ...