我在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”在类型“{}”中缺失。


当前回答

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

可选择的解决方案:

例子:

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)。

其他回答

你可以用一个类实现接口,然后你可以在构造函数中初始化成员:

class IXClass implements IX {
    a: string;
    b: any;
    c: AnotherType;

    constructor(obj: IX);
    constructor(a: string, b: any, c: AnotherType);
    constructor() {
        if (arguments.length == 1) {
            this.a = arguments[0].a;
            this.b = arguments[0].b;
            this.c = arguments[0].c;
        } else {
            this.a = arguments[0];
            this.b = arguments[1];
            this.c = arguments[2];
        }
    }
}

另一种方法是使用工厂函数:

function ixFactory(a: string, b: any, c: AnotherType): IX {
    return {
        a: a,
        b: b,
        c: c
    }
}

然后你可以简单地:

var ix: IX = null;
...

ix = new IXClass(...);
// or
ix = ixFactory(...);

这是我在寻找比我已经得到的更好的方法时偶然发现的。在阅读了答案并尝试了它们之后,我认为值得把我正在做的事情发布出来,因为其他答案对我来说感觉不那么简洁。对我来说,每次设置新界面时只需要编写少量代码是很重要的。我选定了……

使用自定义通用deepCopy函数:

deepCopy = <T extends {}>(input: any): T => {
  return JSON.parse(JSON.stringify(input));
};

定义接口

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

... 并在单独的const中定义默认值。

const XDef : IX = {
    a: '',
    b: null,
    c: null,
};

然后像这样init:

let x : IX = deepCopy(XDef);

这就是所需要的。

. .然而. .

如果你想自定义初始化任何根元素,你可以修改deepCopy函数来接受自定义默认值。函数变成:

deepCopyAssign = <T extends {}>(input: any, rootOverwrites?: any): T => {
  return JSON.parse(JSON.stringify({ ...input, ...rootOverwrites }));
};

然后可以这样调用:

let x : IX = deepCopyAssign(XDef, { a:'customInitValue' } );

任何其他首选的深度复制方式都可以工作。如果只需要一个浅拷贝,那么Object。assign就足够了,不需要使用实用程序deepCopy或deepCopyAssign函数。

let x : IX = object.assign({}, XDef, { a:'customInitValue' });

已知的问题

在这种情况下,它不会深入分配,但并不太难 修改deepCopyAssign以迭代并在赋值前检查类型。 解析/stringify过程将丢失函数和引用。 我的任务不需要这些,OP也不需要。 自定义init值在执行时不会被IDE提示或类型检查。

我使用下面的模式:

创建工具类型默认值<T>:

type OptionalKeys<T> = { [K in keyof T]-?: {} extends Pick<T, K> ? K : never }[keyof T];
type Defaults<T> = Required<Pick<T, OptionalKeys<T>>>

用选项/默认值声明类:

// options passed to class constructor
export interface Options {
    a: string,
    b?: any,
    c?: number
}

// defaults
const defaults: Defaults<Options> = {
    b: null,
    c: 1
};

export class MyClass {
    // all options in class must have values
    options: Required<Options>;

    constructor(options: Options) {
        // merge passed options and defaults
        this.options = Object.assign({}, defaults, options);
    }
}

创建类实例:

const myClass = new MyClass({
    a: 'hello',
    b: true,
});

console.log(myClass.options);
// { a: 'hello', b: true, c: 1 }

另一种方法是使用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)
}

我需要这个React组件。

你可以使用Nullish Coalescing Operator,它会在左手值为Null或Undefined时赋一个默认值:

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

const ixFunction: React.FC<IX> = (props) => {
  console.log(props.b?? "DefaultValue")
}

但这只适用于只在一个地方使用变量的情况。