我在TypeScript中有以下接口:

interface IX {
    a: string,
    b: any,
    c: AnotherType
}

我声明了一个该类型的变量并初始化了所有属性

let x: IX = {
    a: 'abc',
    b: null,
    c: null
}

然后在稍后的init函数中为它们赋值

x.a = 'xyz'
x.b = 123
x.c = new AnotherType()

但我不喜欢在声明对象时为每个属性指定一堆默认空值,因为它们稍后将被设置为实值。我能告诉接口默认属性我不提供为空吗?是什么让我这样做:

let x: IX = {
    a: 'abc'
}

而不会产生编译器错误。现在它告诉我了

TS2322:类型“{}”不能赋值给类型 “九”。属性“b”在类型“{}”中缺失。


当前回答

你可以像文档中解释的那样使用Partial mapped类型: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html

在你的例子中,你会有:

interface IX {
    a: string;
    b: any;
    c: AnotherType;
}

let x: Partial<IX> = {
    a: 'abc'
}

其他回答

您可以使用两个单独的配置。一个作为具有可选属性的输入(将具有默认值),另一个仅具有必需的属性。这可以通过&和Required来方便:

interface DefaultedFuncConfig {
  b?: boolean;
}

interface MandatoryFuncConfig {
  a: boolean;
}

export type FuncConfig = MandatoryFuncConfig & DefaultedFuncConfig;
 
export const func = (config: FuncConfig): Required<FuncConfig> => ({
  b: true,
  ...config
});

// will compile
func({ a: true });
func({ a: true, b: true });

// will error
func({ b: true });
func({});

另一种方法是使用https://www.npmjs.com/package/merge 这和上一个答案是一样的,但是更简洁一些。

让我们安装合并

yarn add -D merge

接下来让我们创建一个带有一些选项的接口。 我们把它放到 / / index.ts类型

export interface ExampleOpts {
    opt1: string,
    opt2: string,
    opt3: string,
}

接下来让我们创建一组默认值 你可以把它放在同一个文件中,但让我们保持类型分离,并将其放入 / config / index.ts

import { ExampleOpts } from '../types'

// Defaults
export const ExampleOptsDefault : ExampleOpts = {
    opt1: 'default value 1',
    opt2: 'default value 2',
    opt3: 'default value 3',
}

接下来让我们用一个函数将它们全部连接在一起 。/ index.ts

import { ExampleOpts } from './types'
import { ExampleOptsDefault } from './config'
import merge from 'merge'

// The ? makes the parameter optional
export function test1(options?: ExampleOpts) {
    // merge tries to load in the defaults first, then options next if it's defined
    const merged_opts: ExampleOpts = merge.recursive(ExampleOptsDefault, options)
    // log the result to the console
    console.log(merged_opts)
}

接口的默认值是不可能的,因为接口只存在于编译时。

可选择的解决方案:

例子:

class AnotherType {}

interface IX {
    a: string,
    b: any,
    c: AnotherType | null
}

function makeIX (): IX {
    return {
    a: 'abc',
    b: null,
    c: null
    }
}

const x = makeIX();

x.a = 'xyz';
x.b = 123;
x.c = new AnotherType();

关于你的例子,我唯一改变的是使属性c both AnotherType |为空。这将是必要的,没有任何编译器错误(这个错误也出现在你的例子中,你初始化为null属性c)。

虽然@Timar的答案是完美的空默认值(什么是被要求的),这里有另一个简单的解决方案,允许其他默认值:定义一个选项接口,以及一个根据常量包含默认值;在构造函数中,使用展开操作符设置options成员变量

interface IXOptions {
    a?: string,
    b?: any,
    c?: number
}

const XDefaults: IXOptions = {
    a: "default",
    b: null,
    c: 1
}

export class ClassX {
    private options: IXOptions;

    constructor(XOptions: IXOptions) {
        this.options = { ...XDefaults, ...XOptions };
    }

    public printOptions(): void {
        console.log(this.options.a);
        console.log(this.options.b);
        console.log(this.options.c);
    }
}

现在你可以像这样使用这个类:

const x = new ClassX({ a: "set" });
x.printOptions();

输出:

set
null
1

这要看情况和用法而定。通常,在TypeScript中,接口没有默认值。

如果您不使用默认值 你可以声明x为:

let x: IX | undefined; // declaration: x = undefined

然后,在你的init函数中,你可以设置实值:

x = {
    a: 'xyz'
    b: 123
    c: new AnotherType()
};

这样,x可以是undefined或defined - undefined表示对象未初始化,如果不需要默认值,则不设置默认值。这在逻辑上比定义“垃圾”要好。

如果你想部分赋值对象: 你可以用可选属性定义类型,比如:

interface IX {
    a: string,
    b?: any,
    c?: AnotherType
}

在这种情况下,您只需要设置a。其他类型用?这意味着它们是可选的,并具有未定义的默认值。

甚至

let x: Partial<IX> = { ... }

这使得所有字段都是可选的。

在任何情况下,你都可以使用undefined作为默认值,这只是取决于你的用例。