Typescript接口默认值

d51*_*512 91 typescript

我在TypeScript中有以下界面:

interface IX {
    a: string,
    b: any,
    c: AnotherType
}
Run Code Online (Sandbox Code Playgroud)

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

let x: IX = {
    a: 'abc',
    b: null,
    c: null
}
Run Code Online (Sandbox Code Playgroud)

然后我稍后在init函数中为它们分配实数值

x.a = 'xyz'
x.b = 123
x.c = new AnotherType()
Run Code Online (Sandbox Code Playgroud)

但是,我不希望在声明对象时,必须为每个属性指定一堆默认的空值,以便稍后将它们设置为实际值.我可以告诉界面默认我不提供给null的属性吗?什么会让我这样做:

let x: IX = {
    a: 'abc'
}
Run Code Online (Sandbox Code Playgroud)

没有得到编译器错误.现在它告诉我

TS2322:类型"{}"不能分配给"IX"类型.类型"{}"中缺少属性"b".

bas*_*rat 75

我可以告诉界面默认我不提供给null的属性吗?什么会让我这样做

不,但默认情况下,它们undefined大多数都很好.您可以使用以下模式,即在创建时具有类型断言:

let x: IX = {} as any;

x.a = 'xyz'
x.b = 123
x.c = new AnotherType()
Run Code Online (Sandbox Code Playgroud)

我在这里记录了这个和其他模式:https://basarat.gitbooks.io/typescript/content/docs/tips/lazyObjectLiteralInitialization.html

  • 使用`any`会破坏*Type*Script的目的.还有其他答案没有这个缺点. (15认同)
  • 您将答案编辑为蒂马尔答案的副本。为什么不直接重定向到他的答案呢? (3认同)
  • 奇怪的是,当basarat在提供的链接中使用“ let foo = {}作为Foo;”提供更好的选择时,将使用“ any”示例。(“ Foo”是接口) (2认同)

小智 63

您不能在界面中设置默认值,但您可以使用可选属性完成您想要的操作(比较段落#3):

https://www.typescriptlang.org/docs/handbook/interfaces.html

只需将界面更改为:

interface IX {
    a: string,
    b?: any,
    c?: AnotherType
}
Run Code Online (Sandbox Code Playgroud)

然后你可以这样做:

let x: IX = {
    a: 'abc'
}
Run Code Online (Sandbox Code Playgroud)

并使用您的init函数为其分配默认值x.b,x.c如果未设置这些属性.

  • @BennyNeugebauer 接受的答案有同样的缺陷。这是最好的答案 (3认同)
  • 为了方便使用接口的人,属性不应标记为“可选”。答案是“不”,您不能“告诉接口提供默认值”,但您可以提供工厂方法来初始化接口的实例。 (3认同)
  • 在这个问题中,要求用`null`初始化`xb`和`xc`。当编写`let x = {a:'abc'}`时,`xb`和`xc`是`undefined`,因此,尽管这是一个明智的快速解决方案,但该答案仍未完全满足要求。 (2认同)

Nit*_*mer 18

您可以使用类实现接口,然后您可以在构造函数中处理初始化成员:

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];
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用工厂功能:

function ixFactory(a: string, b: any, c: AnotherType): IX {
    return {
        a: a,
        b: b,
        c: c
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以简单地说:

var ix: IX = null;
...

ix = new IXClass(...);
// or
ix = ixFactory(...);
Run Code Online (Sandbox Code Playgroud)


vit*_*ets 11

我使用以下模式:

创建实用程序类型Defaults<T>:

type OptionalKeys<T> = { [K in keyof T]-?: {} extends Pick<T, K> ? K : never }[keyof T];
type Defaults<T> = Required<Pick<T, OptionalKeys<T>>>
Run Code Online (Sandbox Code Playgroud)

使用选项/默认值声明类:

// 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

创建类实例:

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

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


Jac*_*ler 10

虽然@Timar的答案对于null默认值(要求的内容)非常有效,但是这里还有一个简单的解决方案,它允许其他默认值:定义一个选项接口以及一个包含默认值的常量;在构造函数中,使用传播运算符设置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);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您可以使用这样的类:

const x = new ClassX({ a: "set" });
x.printOptions();
Run Code Online (Sandbox Code Playgroud)

输出:

set
null
1
Run Code Online (Sandbox Code Playgroud)

  • @ManishRawat 例如,您可以不将任何属性声明为可选,而是让构造函数采用“Partial&lt;IXOptions&gt;”类型。这样 TS 就知道所有属性都将出现在 `this.options` 中,但构造函数中不需要任何属性。 (3认同)

小智 8

您可以Partial按照文档中的说明使用映射类型: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'
}
Run Code Online (Sandbox Code Playgroud)


Wil*_*een 7

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

替代解决方案:

您可以为此使用工厂方法,该方法返回一个实现 XI 接口的对象。

例子:

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();
Run Code Online (Sandbox Code Playgroud)

关于您的示例,我唯一更改的是属性 c Both AnotherType | null。这对于没有任何编译器错误是必要的(如果您将 null 初始化为属性 c,则您的示例中也存在此错误)。


or *_*fer 5

如果您有许多参数,最佳实践是让用户仅插入几个参数并且不按特定顺序插入。

例如,不好的做法:

foo(a?, b=1, c=99, d=88, e?)
foo(null, null, null, 3)
Run Code Online (Sandbox Code Playgroud)

由于您必须在实际需要的参数之前提供所有参数 (d)。

良好的使用习惯是:

foo({d=3})
Run Code Online (Sandbox Code Playgroud)

做到这一点的方法是通过接口。您需要将参数定义为接口,例如:

interface Arguments {
    a?;
    b?; 
    c?;
    d?;
    e?;
}
Run Code Online (Sandbox Code Playgroud)

并将函数定义如下:

foo(arguments: Arguments)
Run Code Online (Sandbox Code Playgroud)

现在接口变量无法获取默认值,那么我们如何定义默认值呢?

很简单,我们为整个界面定义默认值:

foo({
        a,
        b=1,
        c=99,
        d=88,
        e                    
    }: Arguments)
Run Code Online (Sandbox Code Playgroud)

现在如果用户通过:

foo({d=3})
Run Code Online (Sandbox Code Playgroud)

实际参数将是:

{
    a,
    b=1,
    c=99,
    d=3,
    e                    
}
Run Code Online (Sandbox Code Playgroud)

不声明接口的另一种选择是:

foo({
        a=undefined,
        b=1,
        c=99,
        d=88,
        e=undefined                    
    })
Run Code Online (Sandbox Code Playgroud)

跟进: 在前面的函数定义中,我们为参数对象的字段定义了默认值,但没有为对象本身定义默认值。Cannot read property 'b' of undefined因此,我们将从以下调用中得到提取错误(例如):

foo()
Run Code Online (Sandbox Code Playgroud)

有两种可能的解决方案:

1.

const defaultObject = {a=undefined, b=1, c=99, d=88, e=undefined}
function foo({a=defaultObject.a, b=defaultObject.b, c=defaultObject.c, d=defaultObject.d, e=defaultObject.e} = defaultObject)
Run Code Online (Sandbox Code Playgroud)
function foo(object = {}) {
    object = { b=1, c=99, d=88, ...object }
    //Continue the function code..
}
Run Code Online (Sandbox Code Playgroud)

跟进: 如果您需要类型和默认值(并且您不想声明接口),您可以编写:

function foo(params: {a?: string, b?: number, c?: number, d?: number, e?: string}) {
    params = { b:1, c:99, d:88, ...params }
    //Continue the function code..
}
Run Code Online (Sandbox Code Playgroud)