Typescript 接口默认值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35074365/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Typescript interface default values
提问by d512
I have the following interface in TypeScript:
我在 TypeScript 中有以下接口:
interface IX {
a: string,
b: any,
c: AnotherType
}
I declare a variable of that type and I initialize all the properties
我声明了一个该类型的变量并初始化了所有属性
let x: IX = {
a: 'abc',
b: null,
c: null
}
Then I assign real values to them in an init function later
然后我稍后在 init 函数中为它们分配实际值
x.a = 'xyz'
x.b = 123
x.c = new AnotherType()
But I don't like having to specify a bunch of default null values for each property when declaring the object when they're going to just be set later to real values. Can I tell the interface to default the properties I don't supply to null? What would let me do this:
但是我不喜欢在声明对象时必须为每个属性指定一堆默认空值,因为它们稍后将被设置为实际值。我可以告诉界面将我不提供的属性默认为 null 吗?什么会让我这样做:
let x: IX = {
a: 'abc'
}
without getting a compiler error. Right now it tells me
没有得到编译器错误。现在它告诉我
TS2322: Type '{}' is not assignable to type 'IX'. Property 'b' is missing in type '{}'.
TS2322:类型“{}”不可分配给类型“IX”。类型“{}”中缺少属性“b”。
采纳答案by basarat
Can I tell the interface to default the properties I don't supply to null? What would let me do this
我可以告诉界面将我不提供的属性默认为 null 吗?什么会让我这样做
No. But by default they are undefined
which is mostly just fine. You can use the following pattern, i.e have a type assertion at the point of creation:
不。但默认情况下,它们undefined
大多很好。您可以使用以下模式,即在创建时有一个类型断言:
let x: IX = {} as any;
x.a = 'xyz'
x.b = 123
x.c = new AnotherType()
I have this and other patterns documented here : https://basarat.gitbooks.io/typescript/content/docs/tips/lazyObjectLiteralInitialization.html
我在这里记录了这个和其他模式:https: //basarat.gitbooks.io/typescript/content/docs/tips/lazyObjectLiteralInitialization.html
回答by Timar
You can't set default values in an interface, but you can accomplish what you want to do by using Optional Properties (compare paragraph #3):
您不能在界面中设置默认值,但您可以通过使用可选属性来完成您想做的事情(比较第 3 段):
https://www.typescriptlang.org/docs/handbook/interfaces.html
https://www.typescriptlang.org/docs/handbook/interfaces.html
Simply change the interface to:
只需将界面更改为:
interface IX {
a: string,
b?: any,
c?: AnotherType
}
You can then do:
然后你可以这样做:
let x: IX = {
a: 'abc'
}
And use your init function to assign default values to x.b
and x.c
if those properies are not set.
而在你的初始化函数默认值分配给x.b
和x.c
如果这些性的判定都没有设置。
回答by Hyman Miller
While @Timar's answer works perfectly for null
default values (what was asked for), here another easy solution which allows other default values: Define an option interface as well as an according constant containing the defaults; in the constructor use the spread operatorto set the options
member variable
虽然@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);
}
}
Now you can use the class like this:
现在你可以像这样使用这个类:
const x = new ClassX({ a: "set" });
x.printOptions();
Output:
输出:
set
null
1
回答by Nitzan Tomer
You can implement the interface with a class, then you can deal with initializing the members in the constructor:
你可以用一个类来实现接口,然后你可以在构造函数中处理初始化成员:
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];
}
}
}
Another approach is to use a factory function:
另一种方法是使用工厂函数:
function ixFactory(a: string, b: any, c: AnotherType): IX {
return {
a: a,
b: b,
c: c
}
}
Then you can simply:
然后你可以简单地:
var ix: IX = null;
...
ix = new IXClass(...);
// or
ix = ixFactory(...);
回答by F. Bauer
You can use the Partial
mapped type as explained in the documentation:
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html
您可以Partial
按照文档中的说明使用映射类型:https:
//www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html
In your example, you'll have:
在您的示例中,您将拥有:
interface IX {
a: string;
b: any;
c: AnotherType;
}
let x: Partial<IX> = {
a: 'abc'
}
回答by Moss Palmer
I stumbled on this while looking for a better way than what I had arrived at. Having read the answers and trying them out I thought it was worth posting what I was doing as the other answers didn't feel as succinct for me. It was important for me to only have to write a short amount of code each time I set up a new interface. I settled on...
我在寻找比我到达的更好的方法时偶然发现了这一点。阅读答案并尝试后,我认为值得发布我正在做的事情,因为其他答案对我来说并不简洁。每次设置新界面时只需编写少量代码对我来说很重要。我定了...
Using a custom generic deepCopy function:
使用自定义的通用 deepCopy 函数:
deepCopy = <T extends {}>(input: any): T => {
return JSON.parse(JSON.stringify(input));
};
Define your interface
定义你的接口
interface IX {
a: string;
b: any;
c: AnotherType;
}
... and define the defaults in a separate const.
...并在单独的常量中定义默认值。
const XDef : IX = {
a: '',
b: null,
c: null,
};
Then init like this:
然后像这样初始化:
let x : IX = deepCopy(XDef);
That's all that's needed..
这就是所需要的。。
.. however ..
.. 然而 ..
If you want to custom initialise any root elementyou can modify the deepCopy function to accept custom default values. The function becomes:
如果您想自定义初始化任何根元素,您可以修改 deepCopy 函数以接受自定义默认值。函数变为:
deepCopyAssign = <T extends {}>(input: any, rootOverwrites?: any): T => {
return JSON.parse(JSON.stringify({ ...input, ...rootOverwrites }));
};
Which can then be called like this instead:
然后可以这样调用:
let x : IX = deepCopyAssign(XDef, { a:'customInitValue' } );
Any other preferred way of deep copy would work. If only a shallow copy is needed then Object.assign would suffice, forgoing the need for the utility deepCopy
or deepCopyAssign
function.
任何其他首选的深度复制方式都可以使用。如果只需要一个浅拷贝,那么 Object.assign 就足够了,不需要实用程序deepCopy
或deepCopyAssign
函数。
let x : IX = object.assign({}, XDef, { a:'customInitValue' });
Known Issues
已知的问题
- It will not deep assign in this guise but it's not too difficult to
modify
deepCopyAssign
to iterate and check types before assigning. - Functions and references will be lost by the parse/stringify process. I don't need those for my task and neither did the OP.
- Custom init values are not hinted by the IDE or type checked when executed.
- 它不会以这种形式进行深度分配,但
deepCopyAssign
在分配之前修改以迭代和检查类型并不太难。 - 解析/字符串化过程将丢失函数和引用。我的任务不需要那些,OP也不需要。
- IDE 不会提示自定义初始化值,也不会在执行时检查类型。
回答by Luckylooke
My solution:
我的解决方案:
I have created wrapper over Object.assign to fix typing issues.
我在 Object.assign 上创建了包装器来解决打字问题。
export function assign<T>(...args: T[] | Partial<T>[]): T {
return Object.assign.apply(Object, [{}, ...args]);
}
Usage:
用法:
env.base.ts
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
环境.dev.ts
import { EnvironmentValues, enviromentBaseValues } from './env.base';
import { assign } from '../utilities';
export const enviromentDevValues: EnvironmentValues = assign<EnvironmentValues>(
{
apiURL: '/api',
},
enviromentBaseValues
);
export default enviromentDevValues;