在 Typescript 中为类型分配默认值
我想做的是为我的自定义类型中的所有属性分配默认值,如果它们未被定义。
我已经做了这个:
// my custom type with all optional properties
type MyType = {
// a example property:
str?: string
}
// imagine I have hundreds of properties, I can't assign all of them one by one
// so I created a object for default values
const defaultValuesForMyType: MyType = {
str: "hello world!"
}
// passes a string to do something
// imagine it's a function in other API that I can't change
function doThingsWithString(str: string): void {
// do something, doesn't matter, for example:
console.log(str);
}
// passes a object with my custom type
function driver(inputObject: MyType) {
const finalObject: MyType = { ...defaultValuesForMyType, ...inputObject };
doThingsWithString(finalObject.str);
}
但是 VS Code 显示我:
doThingsWithString(finalObject.str);
^~~~~~~~~~~~~~^
Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
Type 'undefined' is not assignable to type 'string'. ts(2345)
const finalObject: {
str?: string | undefined;
}
我以为 finalObject 100% 不是 undefined?🤔
编辑:
@jcalz 的答案有效!
我注意到这是课程的问题,很抱歉 😅
// my custom type with all optional properties
type MyType = {
// a example property:
str?: string
}
// imagine I have hundreds of properties, I can't assign all of them one by one
// so I created a object for default values
const defaultValuesForMyType = {
str: "hello world!"
}
// passes a string to do something
// imagine it's a function in other API that I can't change
function doThingsWithString(str: string): void {
// do something, doesn't matter, for example:
console.log(str);
}
class TestClass {
propObject;
driver(inputObject: MyType) {
this.propObject = { ...defaultValuesForMyType, ...inputObject };
doThingsWithString(this.propObject.str);
}
}
没有错误,但 VS Code 现在说 TestClass#propObject 是 any
答案#1
你已经将 defaultValuesForMyType 的类型标注为 MyType,所以编译器关于 defaultValuesForMyType 仅知道这些信息。初始化对象字面量中的任何更具体的信息都已丢失。str 属性是可选的。这允许你 delete str 属性,这大概也是为什么有人会做这样的标注。就编译器所知或关心的,str 可能是 string 或 undefined。
如果你希望编译器知道 str 属性是 string 并且永远不会是 undefined,那么最好根本不要进行注解。只需让编译器推断它的类型即可:
const defaultValuesForMyType = {
str: "hello world!"
}
/* const defaultValuesForMyType: {
str: string;
} */
在此之后,编译器将理解,将 defaultValuesForMyType 和 MyType 扩展到一个新对象中,会导致 str 属性具有明确的 string 值:
function driver(inputObject: MyType) {
const finalObject = { ...defaultValuesForMyType, ...inputObject };
// const finalObject: { str: string; }
doThingsWithString(finalObject.str); // okay
}
要在类中使其工作,请务必为字段注解类型。因为它在构造函数中没有初始化,所以它可能应该是可选的:
class TestClass {
propObject?: Required<MyType>; // annotate
driver(inputObject: MyType) {
this.propObject = { ...defaultValuesForMyType, ...inputObject };
doThingsWithString(this.propObject.str);
}
}
请注意,我将相关类型写为Required<MyType>,使用Required工具类型生成一个MyType的版本,其中所有属性都是必需的。你也可以同样容易地写成{str: string},但如果你有数百个属性,Required<MyType>可能会更易于扩展。
代码的 Playground 链接
