gpt4 book ai didi

TypeScript 提供(未指定的)泛型类型作为泛型参数

转载 作者:行者123 更新时间:2023-12-05 05:00:39 30 4
gpt4 key购买 nike

我希望提供一个泛型类型作为类型参数而不首先将其解析为具体类型。换句话说,我正在寻找一种方法来指定从基类继承时可以使用的类型映射函数。

示例(不正确的)语法,希望比我能解释得更好:

abstract class RunIt<SomeMagicConverter> {
// The return type for this function depends on the type of the
// argument *and* on the way the implementation class was declared:
run<T>(o: T): SomeMagicConverter<T> { // (syntax error)
return this.handle(o); // (imagine this does something more interesting)
}
protected abstract handle<T>(o: T): SomeMagicConverter<T>; // (syntax error)
}

type MyMagicConverter<T> = TypeIWantToReturn<T>; // MyMagicConverter is generic
class MyRunIt extends RunIt<MyMagicConverter> { // but we don't specify T here
// [...]
}
new MyRunIt().run(7); // call infers T is number, so returns TypeIWantToReturn<number>
new MyRunIt().run(''); // now T is string, so returns TypeIWantToReturn<string>

此外,我想限制它以便 SomeMagicConverter<T> extends SomeBase<T>有保证。即

abstract class RunIt<SomeMagicConverter extends SomeBase>

关于我希望如何使用它的更具体的例子,这里有一个用于缓存包装的基本基类(不完全是我的实际用例,但证明了需要):

interface Wrapped<T> {
contains(other: T): boolean;
}

abstract class Store {
private readonly cached = new Map<any, any>();

protected abstract applyWrap<T>(o: T): Wrapped<T>;

wrap<T>(o: T): Wrapped<T> { // <-- this should return something more specific
if (!this.cached.has(o)) {
this.cached.set(o, this.applyWrap(o));
}
return this.cached.get(o);
}
}

class Foo<T> implements Wrapped<T> {
constructor(private readonly o: T) {}
contains(other: T): boolean { return other === this.o; }
extraFooFunc(): void {}
}

class FooWrapper extends Store {
constructor() { super(); }
protected applyWrap<T>(o: T): Foo<T> { return new Foo<T>(o); }
}

new FooWrapper().wrap(4).extraFooFunc(); // syntax error because extraFooFunc is not defined on Wrapped

显然我可以通过定义包装方法来解决这个问题,但我想避免在每个子类上都这样做:

class FooWrapper extends Store {
// [...]
wrap<T>(o: T): Foo<T> { return super.wrap(o) as Foo<T>; }
}

最佳答案

尚不支持通用通用参数(2021 年 3 月)。参见 TypeScript Issue和一个 similar SO question获取更多信息。

但是,您所描述的可以使用 Indexed Access Types 实现和 Mapped Types :

// Any Converter to be used with RunIt must be added to Converters
interface Converters<T> { }

// All Converters must implement this interface
interface ConverterBase<T> { length: number }

// Maps valid keys to themselves, invalid ones to `never`
type ValidKey<T, K extends keyof Converters<T>> =
Converters<T>[K] extends ConverterBase<T> ? K : never;

// Contains all entries from Converters where the type extends ConverterBase
type ConstrainedConverters<T> = {
[K in keyof Converters<T> as ValidKey<T, K>]: Converters<T>[K];
};

abstract class RunIt<K extends keyof ConstrainedConverters<void>> {
run<T>(o: T): ConstrainedConverters<T>[K] {
return this.handle(o);
}
protected abstract handle<T>(o: T): ConstrainedConverters<T>[K];
}

// Re-open Converters and add some Converters
interface Converters<T> { Id: T, Array: Array<T> }

class ArrayRunIt extends RunIt<'Array'> {
protected handle<T>(o: T) { return [o]; }
}

// @ts-expect-error Type '"Id"' does not satisfy the constraint '"Array"'.(2344)
class IdRunIt extends RunIt<'Id'> {
protected handle<T>(o: T) { return o; }
}

关于TypeScript 提供(未指定的)泛型类型作为泛型参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63023887/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com