我想使用不可变类而不是不可变接口,原因有两个:
doStuff
方法)otherThing
的任何地方都有效,我希望这会导致编译错误)这是我能够提出的最接近我想要的东西:
interface IData4 {
readonly thing1: string;
readonly thing2: string;
}
class Data4 implements IData4 {
readonly thing1: string;
readonly thing2: string;
constructor(that: IData4, props?: Partial<IData4>){
Object.assign(this, that);
if( props ){
Object.assign(this, props);
}
}
doStuff(){
return this.thing1 == this.thing2;
}
}
// more verbose than a normal ctor parameter list, but I like it better anyway
// more readable, and it makes transposition errors less likely when all
// the params are the same type
// I write code to create instances rarely, reading and updating is more frequent
let data4 = new Data4({thing1: "t1", thing2: "t2"});
// GOOD!: error because of "otherThing"
// let other = new Data4({thing1: "t1", thing2: "t2", otherThing: 'blah'});
// GOOD!: error because missing "thing2"
// let other = new Data4({thing1: "t1"});
// this is the usual update case
let data4a = new Data4(data4, {thing2: "t2a"});
log.debug("data4a: " + JSON.stringify(data4a));
// GOOD! error because of "otherThing"
// let other = new Data4(data4, {thing2: "t2b", otherThing: 'blah'});
// BAD! want "otherThing" to cause error
// but I'm unlikely to use this construct, I wouldn't specify the spread
// operator again because I already specified the thing to copy from
let bad2b = new Data4(data4, {...data4, thing2: "t2b", otherThing: 'blah'});
// BAD! want "otherThing" to cause error
// easy to do accidentally because I'm used to using interfaces
let bad2c = new Data4({...data4, thing2: "t2b", otherThing: 'blah'});
let iData: IData4 = {thing1: 't1', thing2: 't2'};
// BAD! want an error about "otherThing"
let iData2 = {...iData, thing2: 't2a', otherThing: 'blah'};
// GOOD! error because of "otherThing"
// let other: IData4 = {thing1: 't1', thing2: 't2', otherThing: 'blah'};
// GOOD! error because lack of "thing2"
// let other: IData4 = {thing1: 't1'};
此构造的问题:
那么,有没有更好的方法呢?
let data4a = new Data4(data4.thing1, "t2a"});
答案 0 :(得分:0)
这不是很好,但我确实找到了一个问题的答案“有没有办法用接口打包功能”?
您可以使用"declaration merging"制作与功能近似的接口:
interface Data7{
readonly thing1: string;
readonly thing2: string;
}
namespace Data7{
export function areThingsEqualLength(value: Data7): boolean {
return value.thing1.length == value.thing2.length;
}
}
let data7: Data7 = {thing1: "t1", thing2: "t2"};
let data7a = {...data7, thing2: "t2a"};
log.debug("data7a: " + JSON.stringify(data7a));
log.debug("same length thing?: " + Data7.areThingsEqualLength(data7));
// GOOD!
// error: "'otherThing' does not exist in type"
// let other7a: Data7 = {thing1: "t1", thing2: "t2a", otherThing: 'blah'};
// GOOD!
// error: "Property 'thing1' is missing in type '{ thing2: string; }'."
// let other7b: Data7 = {thing2: 't2b'};
// BAD!
// want it to fail on 'otherThing'
let data7b = {...data7, otherThing: 'blah'};
// VERY BAD!
// allows creation of an invalid object.
// The function call will explode, even though it's written correctly
let badData7 = {...data7, thing2: undefined};
// log.debug("same length thing?: " + Data7.areThingsEqualLength(badData7));
如果愿意,您可以使用导入将Data7.areThingsEqualLength(data7)
变为areThingsEqualLength(data7)
。
但我也意识到我可能想避免使用接口:使用它们附带的spread
运算符,它们允许构造无效对象(请参阅“非常糟糕!”注释)。
所以标题问题仍然存在(也许这不应该是一个答案,也许它应该是对问题的编辑,但那时它会很长)。