我在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 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(...);

其他回答

我能告诉接口默认属性我不提供为空吗?是什么让我这么做的

不。不能为接口或类型别名提供默认值,因为它们仅在编译时使用,并且默认值需要运行时支持

替代

但是没有指定的值在JavaScript运行时默认为undefined。所以你可以把它们标记为可选:

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

现在当你创建它时,你只需要提供一个:

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

你可以根据需要提供这些值:

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

这要看情况和用法而定。通常,在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作为默认值,这只是取决于你的用例。

我的解决方案:

我在对象上创建了包装器。指派以修复键入问题。

export function assign<T>(...args: T[] | Partial<T>[]): T {
  return Object.assign.apply(Object, [{}, ...args]);
}

用法:

env.base.ts

export interface EnvironmentValues {
export interface EnvironmentValues {
  isBrowser: boolean;
  apiURL: string;
}

export const enviromentBaseValues: Partial<EnvironmentValues> = {
  isBrowser: typeof window !== 'undefined',
};

export default enviromentBaseValues;

env.dev.ts

import { EnvironmentValues, enviromentBaseValues } from './env.base';
import { assign } from '../utilities';

export const enviromentDevValues: EnvironmentValues = assign<EnvironmentValues>(
  {
    apiURL: '/api',
  },
  enviromentBaseValues
);

export default enviromentDevValues;

虽然@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

您还可以使用helper方法/函数返回具有默认属性值的对象,然后调用代码可以根据需要重写默认值。这就是我在当前项目中遇到同样问题时所遵循的方法。通过这种方式,对默认属性值对象进行编码是一次性的事情,您可以在整个应用程序中重用该对象。