对我有用的解决方案
interface FrameworkMethodOptionsPart1 {
aProperty?: string[];
anotherProperty?: boolean;
}
type FrameworkMethodOptionsPart2<T> = {
[P in keyof T]?: OptionsCallBack
}
type FrameworkMethodOptions<T> = FrameworkMethodOptionsPart1 | FrameworkMethodOptionsPart2<T>;
对于未来的参考 porpuses,下面是我尝试过的所有替代方案,以防 Playground Link 停止工作。
您需要将代码复制并粘贴到启用打字稿的 ide/代码编辑器中才能查看错误。
//imagine this is the framework declarations
interface $ {
frameWorkMethod<T>(first: T, options: FrameworkMethodOptions<T>): object;
}
interface FrameworkMethodOptions<T> {
aProperty?: string[];
anotherProperty?: boolean;
[P in keyof T]?: OptionsCallBack;
}
interface OptionsCallBack {
create?: () => void;
update?: () => void;
}
var user: User = { name: "leonardo", age: 33 };
interface User {
name: string;
age: number;
}
var example1: FrameworkMethodOptions<any> = {
aProperty: ["this is string", " ignoreThis"]
};
var example2: FrameworkMethodOptions<any> = {
aProperty: ["this is string", " ignoreThis"],
address: { create: () => { console.log("ah") } }
};
var example3: FrameworkMethodOptions<User> = {
aProperty: ["this is string", " ignoreThis"],
age: { create: () => { console.log("ah") } }
};
var example4: FrameworkMethodOptions<User> = {
aProperty: ["this is string", " ignoreThis"],
};
var example5: FrameworkMethodOptions<User> = {
age: { create: () => { console.log("ah") } }
};
var example6: FrameworkMethodOptions<User> = {};
var example7: FrameworkMethodOptions<any> = {};
var invalidExample1: FrameworkMethodOptions<User> = {
address: { create: () => { console.log("ah") } } //Address ist not part of User interface
};
////////////////////////////////////////////////////////////////////
//B Alternative Idea
interface FrameworkMethodOptionsPart1 {
aProperty?: string[];
anotherProperty?: boolean;
}
type FrameworkMethodOptionsPart2<T> = {
[P in keyof T]?: OptionsCallBack
}
type FrameworkMethodOptionsB<T> = FrameworkMethodOptionsPart1 & FrameworkMethodOptionsPart2<T>;
var example1b: FrameworkMethodOptionsB<any> = {
aProperty: ["this is string", " ignoreThis"]
};
var example2b: FrameworkMethodOptionsB<any> = {
aProperty: ["this is string", " ignoreThis"],
address: { create: () => { console.log("ah") } }
};
var example3b: FrameworkMethodOptionsB<User> = {
aProperty: ["this is string", " ignoreThis"],
age: { create: () => { console.log("ah") } }
};
var example4b: FrameworkMethodOptionsB<User> = {
aProperty: ["this is string", " ignoreThis"],
};
var example5b: FrameworkMethodOptionsB<User> = {
age: { create: () => { console.log("ah") } }
};
var example6b: FrameworkMethodOptionsB<User> = {};
var example7b: FrameworkMethodOptionsB<any> = {};
var invalidExample1b: FrameworkMethodOptionsB<User> = {
address: { create: () => { console.log("ah") } } //Address is not part of User interface
};
/////////////////////////////////////////////////////////////////
// C Alternative Idea
type FrameworkMethodOptionsC<T> = any extends T
? FrameworkMethodOptionsPart1
: FrameworkMethodOptionsPart1 & FrameworkMethodOptionsPart2<T>;
var example1c: FrameworkMethodOptionsC<any> = {
aProperty: ["this is string", " ignoreThis"]
};
var example2c: FrameworkMethodOptionsC<any> = {
aProperty: ["this is string", " ignoreThis"],
address: { create: () => { console.log("ah") } }
};
var example3c: FrameworkMethodOptionsC<User> = {
aProperty: ["this is string", " ignoreThis"],
age: { create: () => { console.log("ah") } }
};
var example4c: FrameworkMethodOptionsC<User> = {
aProperty: ["this is string", " ignoreThis"],
};
var example5c: FrameworkMethodOptionsC<User> = {
age: { create: () => { console.log("ah") } }
};
var example6c: FrameworkMethodOptionsC<User> = {};
var example7c: FrameworkMethodOptionsC<any> = {};
var invalidExample1c: FrameworkMethodOptionsC<User> = {
address: { create: () => { console.log("ah") } } //Address is not part of User interface
};
/////////////////////////////////////////////////////////////////
// D Alternative Idea
type FrameworkMethodOptionsPart2Untyped = {
[key: string]: OptionsCallBack // TS DOESNT ALLOW THIS TO BE OPTIONAL
}
type FrameworkMethodOptionsD<T> = any extends T
? FrameworkMethodOptionsPart1 & FrameworkMethodOptionsPart2Untyped
: FrameworkMethodOptionsPart1 & FrameworkMethodOptionsPart2<T>;
var example1d: FrameworkMethodOptionsD<any> = {
aProperty: ["this is string", " ignoreThis"]
};
var example2d: FrameworkMethodOptionsD<any> = {
aProperty: ["this is string", " ignoreThis"],
address: { create: () => { console.log("ah") } }
};
var example3d: FrameworkMethodOptionsD<User> = {
aProperty: ["this is string", " ignoreThis"],
age: { create: () => { console.log("ah") } }
};
var example4d: FrameworkMethodOptionsD<User> = {
aProperty: ["this is string", " ignoreThis"],
};
var example5d: FrameworkMethodOptionsD<User> = {
age: { create: () => { console.log("ah") } }
};
var example6d: FrameworkMethodOptionsD<User> = {};
var example7d: FrameworkMethodOptionsD<any> = {};
var invalidExample1d: FrameworkMethodOptionsD<User> = {
address: { create: () => { console.log("ah") } } //Address is not part of User interface
};
/////////////////////////////////////////////////////////////////
// E Alternative Idea
type FrameworkMethodOptionsE<T> = FrameworkMethodOptionsPart1 & FrameworkMethodOptionsPart2Untyped
var example1e: FrameworkMethodOptionsE<any> = {
aProperty: ["this is string", " ignoreThis"]
};
var example2e: FrameworkMethodOptionsE<any> = {
aProperty: ["this is string", " ignoreThis"],
address: { create: () => { console.log("ah") } }
};
var example3e: FrameworkMethodOptionsE<User> = {
aProperty: ["this is string", " ignoreThis"],
age: { create: () => { console.log("ah") } }
};
var example4e: FrameworkMethodOptionsE<User> = {
aProperty: ["this is string", " ignoreThis"],
};
var example5e: FrameworkMethodOptionsE<User> = {
age: { create: () => { console.log("ah") } }
};
var example6e: FrameworkMethodOptionsE<User> = {};
var example7e: FrameworkMethodOptionsE<any> = {};
var invalidExample1e: FrameworkMethodOptionsE<User> = {
address: { create: () => { console.log("ah") } } //Address is not part of User interface
};
/////////////////////////////////////////////////////////////////
// F Alternative Idea. THIS ONE WORKS. !!!!!!!!!!!!!!!!!!!!!!!!!
type FrameworkMethodOptionsF<T> = FrameworkMethodOptionsPart1 | FrameworkMethodOptionsPart2<T>;
var example1f: FrameworkMethodOptionsF<any> = {
aProperty: ["this is string", " ignoreThis"]
};
var example2f: FrameworkMethodOptionsF<any> = {
aProperty: ["this is string", " ignoreThis"],
address: { create: () => { console.log("ah") } },
anythingGoes: 42
};
var example3f: FrameworkMethodOptionsF<User> = {
aProperty: ["this is string", " ignoreThis"],
age: { create: () => { console.log("ah") } }
};
var example4f: FrameworkMethodOptionsF<User> = {
aProperty: ["this is string", " ignoreThis"],
};
var example5f: FrameworkMethodOptionsF<User> = {
age: { create: () => { console.log("ah") } }
};
var example6f: FrameworkMethodOptionsF<User> = {};
var example7f: FrameworkMethodOptionsF<any> = {};
var invalidExample1f: FrameworkMethodOptionsF<User> = {
address: { create: () => { console.log("ah") } } //Expect error. Address is not part of User interface
};
var invalidExample2f: FrameworkMethodOptionsF<User> = {
age: { create: () => { console.log("ah") } },
address: { create: () => { console.log("ah") } } //Expect error. Address is not part of User interface
};
var invalidExample3f: FrameworkMethodOptionsF<User> = {
aProperty: ["this is string", " ignoreThis"],
address: { create: () => { console.log("ah") } } //Expect error. Address is not part of User interface
};
var invalidExample4f: FrameworkMethodOptionsF<User> = {
aProperty: 42, //Expect error. aProperty's type is string[]
};