我正在做一個專案,我需要實體化一個特定類的多個副本,但使用不同的引數。我正在創建一個實用程式函式withAlteredConstructorArgs來幫助我解決這個問題,但是我無法完全正確地獲取型別。
這是我想如何使用此實用程式的示例:
const createCycler = withAlteredConstructorArgs(
Cycler,
function reverseElementArgs<T>(elements: Array<T>): [Array<T>] {
return [elements.reverse()];
}
);
const cycler = createCycler(['foo', 'bar', 'baz', 'quux']);
console.log(cycler.get(), cycler.get());
// > should log 'quux', 'baz'
我撰寫的函式按預期作業,但沒有按我預期的方式檢查型別。我創建了一個TypeScript Playground來充分演示,但這里是實作:
function withAlteredConstructorArgs<Args extends Array<any>, T>(
c: { new(...args: Args): T },
fn: (...args: Args) => Args
): (...args: Args) => T {
return (...args: Args) => new c(...fn(...args))
}
我意識到我沒有T足夠的約束,這就是我收到錯誤訊息的原因:'any[]' is assignable to the constraint of type 'Elements', but 'Elements' could be instantiated with a different subtype of constraint 'any[]'. 我理解這個錯誤并且之前已經修復它,但不是與類建構式引數相關的問題。正確約束建構式引數的正確語法是什么T?
我意識到我可以通過創建一個工廠函式并從問題陳述中完全洗掉建構式來解決這個問題,但我覺得理解這種方法會更好地提高我對 TypeScript 的總體理解。另外,我在工廠方法中遇到了類似的問題,所以似乎建構式方法無論如何都是要走的路。
uj5u.com熱心網友回復:
正確約束建構式引數的正確語法是什么
T?
我以為我根據您撰寫的代碼理解了您的問題,直到我讀到它,這讓我不太確定您希望哪個引數成為創建約束的型別資訊的提供者以及您希望成為哪個引數約束。
我將根據您撰寫代碼的方式做出回應:您希望建構式的引數作為第一個引數提供,以提供 的型別資訊Args,并讓回呼函式采用該型別的引數。
混亂的電位點可以是多維陣列:所述Args是引數陣列,并且為你的類的建構式Cycler接受一個陣列作為它的第一個和唯一的一個引數(因此,一陣列中的陣列)。
這里另一個潛在的混淆點是您似乎想要更高級的型別,但這在 TypeScript 中不可用(至少目前是這樣)。看起來您想要createCycler泛型(它不在您的示例中),并且您可以通過對其使用泛型型別斷言使其成為泛型。(在其他情況下,您可以使用泛型型別注釋,但我認為這在這里不起作用。)
TS游樂場
// Define the function:
type Fn<
Params extends unknown[] = any[],
Result = any,
> = (...params: Params) => Result;
type Ctor<
Params extends unknown[] = any[],
Result = any,
> = new (...params: Params) => Result;
// > = { new (...params: Params): Result }; // Alt syntax
function withAlteredConstructorArgs<C extends Ctor>(
ctor: C,
fn: Fn<ConstructorParameters<C>, ConstructorParameters<C>>,
): Fn<ConstructorParameters<C>, InstanceType<C>> {
return (...args: ConstructorParameters<C>) => new ctor(...fn(...args));
}
// Use:
// First, an example using a simpler class which DOESN'T take a generic array
// and then use it as the type for its first constructor parameter:
class Person {
constructor (readonly first: string, readonly last: string) {}
log () {
console.log(this.first, this.last);
}
}
const createPerson = withAlteredConstructorArgs(
Person,
(
first, // correctly inferred as string
last, // again, string
) => [
first.toLowerCase(),
last.toUpperCase()
] as [string, string], // TS doesn't infer tuples, so an assertion is needed here
);
const p = createPerson('Wolfgang', 'Mozart');
p.log() // "wolfgang" "MOZART"
// Now, your Cycler class:
class Cycler<Elements extends Array<any>> {
private index = 0;
constructor(private elements: Elements) {}
get() {
const el = this.elements[this.index];
this.index;
this.index %= this.elements.length
return el
}
}
// I inferred that you want this to be generic:
// so that the types of the arguments passed to the function that it RETURNS
// will be used for the resulting Cycler instance
const createCycler = withAlteredConstructorArgs(
Cycler,
(elements) => [elements.reverse()] as [unknown[]],
) as <T extends any[]>(elements: T) => Cycler<T>;
const cycler = createCycler(['foo', 'bar', 'baz', 'quux']); // Cycler<string[]>
console.log(cycler.get(), cycler.get()); // "quux" "baz"
uj5u.com熱心網友回復:
通過以下更改,我能夠讓您的代碼編譯并生成預期的輸出:
- 將
Cyclerfrom的定義更改class Cycler<Elements extends Array<any>>為class Cycler<E>。 - 將
Cycler的建構式的簽名從更改constructor(private elements: Elements)為constructor(private elements: E[])。
TS游樂場
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/396647.html
上一篇:打字稿如何從類建構式引數推斷型別
