从a previous question of mine开始,我希望将作为å‚数的通用å‚æ•°ç±»åž‹çš„æ˜ å°„è½¬å‘为作为å‚æ•°ä¼ é€’çš„å›žè°ƒã€‚æˆ‘çš„æ„¿æœ›æ˜¯ä¼ é€’ä»»æ„æ•°é‡çš„æž„é€ å‡½æ•°ï¼Œä½¿ç”¨è¿™äº›æž„é€ å‡½æ•°æž„é€ å®žä¾‹ï¼Œç„¶åŽå°†å®žä¾‹è½¬å‘给回调。
我目å‰æ£åœ¨æ‰§è¡Œæ¤æ“作,其ä¸å‚æ•°åªæ˜¯å›žè°ƒçš„数组,但是在è¯æ³•ä¸Šä¸æ–¹ä¾¿ï¼Œå¹¶ä¸”TypeScript在验è¯æ供的回调具有æ£ç¡®ç¾åæ–¹é¢ä¹Ÿæ²¡æœ‰æ供任何工具帮助。如果您看下é¢çš„代ç ,您应该会明白我的æ„图。我希望能够为回调(而ä¸æ˜¯æ•°ç»„)指定常规å‚数,并且如果回调具有ä¸å…¼å®¹çš„ç¾å,则会出现TypeScript错误。
TypeScriptå¯ä»¥è¿™æ ·åšå—?如果å¯ä»¥ï¼Œæ€Žä¹ˆåŠžï¼Ÿ
class Component {}
class One extends Component { public a = 1; }
class Two extends Component { public b = 2; }
type CompCon = new (...args: any) => Component;
function receive(one: One, two: Two) { console.log(`one: ${one.a}, two: ${two.b}`) }
function wrongReceive(a: string, b: number) { console.log(`a: ${a}, b: ${b}`) }
function example<T extends Array<CompCon>>(
callback: (...args: ???) => void,
...constructors: T
): void {
let instances = constructors.map( (c: CompCon) => new c() );
callback(...instances);
}
example(receive, One, Two); // should be ok
example(wrongReceive, One, Two); // should have typescript compile errors on wrongReceive having wrong signature
example((c: One, d: Two) => { // should be ok
console.log(`c: ${c.a}, d: ${d.b}`);
});
ç”案 0 :(得分:1)
您å¯ä»¥è¿™æ ·åšã€‚定义Ctor
:
type Ctor<C> = new (...args: any[]) => C;
Ctor<C>
是一ç§â€œå¯ä»¥ç”¨new
è°ƒç”¨å¹¶æž„é€ C
的东西â€çš„类型
然åŽæ‚¨å¯ä»¥å®šä¹‰CtorsOf
:
type CtorsOf<T> = { [K in keyof T]: Ctor<T[K]> };
如果T
是类型的元组,则CtorsOf<T>
会生æˆä¸€ä¸ªå…ƒç»„,该元组期望æ¯ç§T
ç±»åž‹çš„æž„é€ å‡½æ•°ã€‚ä¾‹å¦‚ã€‚ CtorsOf<[One, Two]>
将解æžä¸º[Ctor<One>, Ctor<Two>]
。
然åŽæ‚¨å¯ä»¥åƒè¿™æ ·å®šä¹‰example
:
function example<C extends Component[]>(
callback: (...args: C) => void,
...constructors: CtorsOf<C>
): void {
let instances = constructors.map(c => new c()) as C;
callback(...instances);
}
C
是一个元组,定义了您希望在回调ä¸ä½¿ç”¨çš„å‚数的类型,然åŽä»Žè¯¥å…ƒç»„ä¸æ´¾ç”Ÿå‡º...constructors
å‚æ•°çš„æž„é€ å‡½æ•°çš„å…ƒç»„ã€‚
我没有办法é¿å…let instances = ... as C
ä¸çš„类型声明。那里的问题是constructors
的元组会通过.map
æ“作丢失,并且结果数组的类型为Component[]
。我å°è¯•äº†ä¸€äº›å˜ä½“,但是å³ä½¿ä½¿ç”¨äº†([1, "2"] as [number, string]).map(x => x);
è¿™æ ·çš„ç碎内容,原始数组的元组也会丢失,TS会为生æˆçš„(string | number)[]
数组推æ–出最终类型。
以下是从您的原始æ¥æºæ”¹ç¼–而æˆçš„完整示例:
class Component {}
class One extends Component { public a = 1; }
class Two extends Component { public b = 2; }
function receive(one: One, two: Two) { console.log(`one: ${one.a}, two: ${two.b}`) }
function wrongReceive(a: string, b: number) { console.log(`a: ${a}, b: ${b}`) }
// Ctor<C> is a type for "something which can be called with new and constructs a C"
type Ctor<C> = new (...args: any[]) => C;
// Given T a tuple of types, CtorsOf<T> produces a tuple which expects a constructor
// for each type of T. Eg. CtorsOf<[One, Two]> would be [Ctor<One>, Ctor<Two>]
type CtorsOf<T> = { [K in keyof T]: Ctor<T[K]> };
// If you uncomment this and use an editor that shows you what Q expands to, you'll see that
// it expands to [Ctor<One>, Ctor<Two>].
// type Q = CtorsOf<[One, Two]>;
function example<C extends Component[]>(
callback: (...args: C) => void,
...constructors: CtorsOf<C>
): void {
let instances = constructors.map(c => new c()) as C;
callback(...instances);
}
example(receive, One, Two); // This is okay.
example((c: One, d: Two) => { // This is okay.
console.log(`c: ${c.a}, d: ${d.b}`);
}, One, Two);
// example(wrongReceive, One, Two); // Fails to compile.
// example(receive, Two, One); // Fails to compile.
class TwoPrime extends Two { public bPrime = 1; };
example(receive, One, TwoPrime); // This is okay too. TwoPrime is a subclass of Two.
function receivePrime(one: One, two: TwoPrime) { console.log(`one: ${one.a}, two: ${two.b}`) }
example(receivePrime, One, TwoPrime); // This is okay.
// example(receivePrime, One, Two); // Fails to compile. The shape of Two is not compatible with TwoPrime.
const z = ([1, "2"] as [number, string]).map(x => x);