我敢肯定,对于这种典型模式,有一个优雅的解决方案,但是我很难理解如何以类型保存的方式正确地增量创建对象。 基本上,我只想通过先创建一个空对象然后添加所需的属性来创建具有预定义类型的对象。 (我确实知道立即创建它不会导致此问题,但是我的用例需要增量创建)
以下示例显示了我一直在尝试的选项以及每种方法的问题:
export function today() {}
export function yesterday() {}
export function tomorrow() {}
const actionMap = {
TODAY: today,
YESTERDAY: yesterday,
TOMORROW: tomorrow
}
export function out(input) {
actionMap[input]();
}
答案 0 :(得分:4)
您有两个选择:
Expandable
。此类型允许根据需要创建对象。
interface Expandable {
extend<T>(properties: T): this & T;
}
从一个空对象开始,并在合适时向其添加属性。
declare const base: Expandable;
const result: MyType =
base
.extend({ foo: 'hello '})
.extend({ bar: 42 });
如果在扩展基础时需要IntelliSense,则可以通过使Expandable
通用来实现。可能的实现:
type Slice<T> = { [P in keyof T]: Pick<T, P> }[keyof T];
class Extendable<T> {
extend<U extends Slice<T>>(properties: U): this & U {
return Object.assign(this, properties);
}
}
function create(): MyType {
const base = new Extendable<MyType>();
return base
.extend({ foo: 'hello' })
.extend({ bar: 42 })
}
答案 1 :(得分:1)
您可以将MyType
字段设为可选。
type MyType = {
foo?: string;
bar?: number;
};
但是这种方法导致“未定义”检查。
或者您可以简单地使用其他变量并最终创建一个具有预期类型的对象。
type MyType = {
foo: string,
bar: number,
};
function create(): MyType {
const foo = 'foo';
const bar = 0;
return {
foo,
bar
}; // infers type
}
可能不是很优雅,但是可以保持类型安全。
答案 2 :(得分:1)
您可以使用Object.assign
从之前创建的零件中创建对象。 Object.assign
的结果是所有参数类型的交集。这意味着,如果您忘记了某个属性或属性类型错误,则结果将与myType
interface myType { foo: string, bar: number }
function createB(): myType {
const oFoo = { foo: 'foo' };
const oBar = { bar: 0 };
return Object.assign(oFoo, oBar);
}
function createC(): myType {
const oFoo = { foo2: 'foo' };
const oBar = { bar: 0 };
return Object.assign(oFoo, oBar); // err foo is missing
}
function createD(): myType {
const oFoo = { foo: 'foo' };
const oBar = { bar: "0" };
return Object.assign(oFoo, oBar); // err bar is string
}
这不会保护您免受多余属性的影响,因为该检查仅针对对象文字进行:
function createB(): myType {
const oFoo = { foo: 'foo', foo2: 0 };
const oBar = { bar: 0 };
return Object.assign(oFoo, oBar); // still ok
}