网站搜索

在 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 链接