Typescript接口默认值
我在TypeScript中有以下界面:Typescript接口默认值,typescript,Typescript,我在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() 但我不喜欢在声明对象时为每个属性指定一组
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()
但我不喜欢在声明对象时为每个属性指定一组默认的null值,而这些属性稍后将被设置为实值。我可以告诉接口将我没有提供的属性默认为null吗?我该怎么做:
let x: IX = {
a: 'abc'
}
没有得到编译器错误。现在它告诉我
TS2322:类型“{}”不可分配给类型
“九”。类型“{}”中缺少属性“b”
我可以告诉接口将我没有提供的属性默认为null吗?什么会让我这么做
不可以。您不能为接口或类型别名提供默认值,因为它们仅在编译时提供,并且默认值需要运行时支持
可供替代的
但在JavaScript运行时中,未指定的值默认为未定义的
。因此,您可以将它们标记为可选:
interface IX {
a: string,
b?: any,
c?: AnotherType
}
现在,当您创建它时,您只需要提供a
:
let x: IX = {
a: 'abc'
};
您可以根据需要提供值:
x.a = 'xyz'
x.b = 123
x.c = new AnotherType()
可以使用类实现接口,然后可以在构造函数中初始化成员:
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
}
}
deepCopy = <T extends {}>(input: any): T => {
return JSON.parse(JSON.stringify(input));
};
然后你可以简单地:
var ix: IX = null;
...
ix = new IXClass(...);
// or
ix = ixFactory(...);
您不能在接口中设置默认值,但可以通过使用可选属性来完成您想要做的事情(比较第3段): 只需将界面更改为:
interface IX {
a: string,
b?: any,
c?: AnotherType
}
然后,您可以执行以下操作:
let x: IX = {
a: 'abc'
}
如果未设置这些属性,请使用init函数为
x.b
和x.c
分配默认值。而@Timar的答案对于null
默认值(所要求的)非常有效,这里是另一个允许其他默认值的简单解决方案:定义一个选项接口以及包含默认值的相应常量;在构造函数中,使用设置选项
成员变量
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();
let x : IX = deepCopy(XDef);
输出:
set
null
1
我是在寻找一种比我所得到的更好的方法时偶然发现这一点的。在阅读了答案并尝试了它们之后,我认为我所做的是值得的,因为其他答案对我来说并不简洁。每次设置新接口时,只需编写少量代码对我来说很重要。我决定 使用自定义通用deepCopy函数:
function ixFactory(a: string, b: any, c: AnotherType): IX {
return {
a: a,
b: b,
c: c
}
}
deepCopy = <T extends {}>(input: any): T => {
return JSON.parse(JSON.stringify(input));
};
。。。并在单独的常量中定义默认值
const XDef : IX = {
a: '',
b: null,
c: null,
};
然后像这样初始化:
const x = new ClassX({ a: "set" });
x.printOptions();
let x : IX = deepCopy(XDef);
这就是所需要的
。。但是..
如果要自定义初始化任何根元素,可以修改deepCopy函数以接受自定义默认值。该功能变为:
deepCopyAssign = <T extends {}>(input: any, rootOverwrites?: any): T => {
return JSON.parse(JSON.stringify({ ...input, ...rootOverwrites }));
};
任何其他首选的深度复制方式都可以。如果只需要一个浅拷贝,那么Object.assign就足够了,不再需要实用工具deepCopy
或deepcopysign
功能
let x : IX = object.assign({}, XDef, { a:'customInitValue' });
已知问题
- 它不会以这种形式进行深度分配,但也不太难实现
修改
以在分配之前迭代并检查类型deepcopysign
- 解析/字符串化过程将丢失函数和引用。 我的任务不需要这些,OP也不需要
- 执行时,IDE或检查的类型不会提示自定义init值
部分
映射类型:
在您的示例中,您将有:
interface IX {
a: string;
b: any;
c: AnotherType;
}
let x: Partial<IX> = {
a: 'abc'
}
接口IX{
a:弦;
b:有;
c:另一种类型;
}
设x:Partial={
a:‘abc’
}
我的解决方案:
我已经在Object.assign上创建了包装器来修复键入问题
导出函数赋值(…参数:T[]|部分[]):T{
返回Object.assign.apply(对象,[{},…args]);
}
用法:
环境基地
导出接口环境值{
导出接口环境值{
isBrowser:布尔型;
apiURL:字符串;
}
导出常量EnvironmentBaseValues:部分={
isBrowser:typeof window!==“未定义”,
};
导出默认的EnvironmentBaseValue;
环境发展小组
从“/env.base”导入{EnvironmentValues,environmentbasevalues};
从“../utilities”导入{assign};
export const environmentdevvalues:EnvironmentValues=assign(
{
APIRL:“/api”,
},
环境基本值
);
导出默认环境devvalue;
您可以使用两个单独的配置。一个作为具有可选属性(将具有默认值)的输入,另一个仅具有必需的属性。这可以通过&
和必需的实现:
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({});
接口DefaultedFuncConfig{
b?:布尔型;
}
接口MandatoryFuncConfig{
a:布尔型;
}
导出类型FuncConfig=MandatoryFuncConfig&DefaultedFuncConfig;
导出常量func=(配置:FuncConfig):必需=>({
b:是的,
…配置
});
//将编译
func({a:true});
func({a:true,b:true});
//会出错吗
func({b:true});
func({});
这取决于大小写和用法。通常,在TypeScript中,接口没有默认值
如果不使用默认值
您可以将x
声明为:
let x: IX | undefined; // declaration: x = undefined
然后,在init函数中可以设置实际值:
x = {
a: 'xyz'
b: 123
c: new AnotherType()
};
这样,x
可以是未定义的或已定义的-未定义的
表示对象未初始化,如果不需要,则不设置默认值。这在逻辑上优于定义“垃圾”
如果要部分分配对象:
您可以使用以下可选属性定义类型:
interface IX {
a: string,
b?: any,
c?: AnotherType
}
在这种情况下,您只需设置a
。其他类型用?
标记,这意味着它们是可选的,默认值为未定义
甚至
let x: Partial<IX> = { ... }
foo({d=3})
interface Arguments {
a?;
b?;
c?;
d?;
e?;
}
foo(arguments: Arguments)
foo({
a,
b=1,
c=99,
d=88,
e
}: Arguments)
foo({d=3})
{
a,
b=1,
c=99,
d=3,
e
}