使用嵌套类型参数而不在TS中声明两次

时间:2018-03-23 22:07:05

标签: typescript generics

是否可以在TypeScript中执行类似this的操作?

如果没有,是否有正式解释为什么编译器无法推断嵌套类型参数?

以下是我尝试实现的一个例子:

interface TestFilter {
    name?: string;
}

interface FilterComponent<F> {
    setFilter(filter: F)
}

class TestFilterComponent implements FilterComponent<TestFilter> {
    private filter: TestFilter;

    setFilter(filter: TestFilter) {
        this.filter = filter;
    }
}

// Can I use F without declaring it as another type parameter?
// Something like: class FilterWrapperComponent<FC extends FilterComponent<F>>
abstract class FilterWrapperComponent<F, FC extends FilterComponent<F>> {
    private sidebarFilter: FC;
    private modalFilter: FC;

    public passFilter(filter: F) {
        this.sidebarFilter.setFilter(filter);
        this.modalFilter.setFilter(filter);
    }
}

// I want to just write "extends FilterWrapperComponent<TestFilterComponent>"
// and get TestFilter as F automatically
class TestFilterWrapperComponent extends FilterWrapperComponent<TestFilter, TestFilterComponent> {

}

也可在playground上找到。

3 个答案:

答案 0 :(得分:1)

您可以在当前处于候选发布候选状态的TypeScript 2.8中安装typescript@rc

TypeScript 2.8附带条件类型和条件类型的类型推断。你真正想要的是通用约束中的类型推断,但这不是直接可能的,解决方法是使用在else分支中解析为never的条件类型。

interface FilterComponent<F = any> {
    setFilter(filter: F)
}

type ExtractFilter<C extends FilterComponent> = C['setFilter'] extends (filter: infer F) => void ? F : never;

现在你可以像这样编写你的类:

abstract class FilterWrapperComponent<FC extends FilterComponent> {
    private sidebarFilter: FC;
    private modalFilter: FC;

    public passFilter(filter: ExtractFilter<FC>) {
        this.sidebarFilter.setFilter(filter);
        this.modalFilter.setFilter(filter);
    }
}

class TestFilterWrapperComponent extends FilterWrapperComponent<TestFilterComponent> {
}

答案 1 :(得分:1)

默认情况下,通用参数值为{}。它在省略参数时适用。可以使用generic parameter defaults更改默认值。

  

我想写“extends FilterWrapperComponent”   并自动将TestFilter作为F

这可以通过仅指定FilterComponent<TestFilter>来获得TestFilterTestFilter的相反方式:

abstract class FilterWrapperComponent<F, FC = FilterComponent<F>> {}

class TestFilterWrapperComponent extends FilterWrapperComponent<TestFilter> {}

答案 2 :(得分:1)

使用 infer 语句,您可以推断类型 inside conditional types

这意味着您可以提取另一种类型中“隐藏”的类型。 接下来,我编写了 UnwrapFilter,它从 Filter 类型中提取 FilterComponent 泛型参数。

type UnwrapFilter<T extends FilterComponent<any>> = T extends FilterComponent<infer TC> ? TC : never;

abstract class FilterWrapperComponent2<FC extends FilterComponent<any>> {
    constructor(
      private sidebarFilter: FC,
      private modalFilter: FC,
    ) {}

    public passFilter(filter: UnwrapFilter<FC>) {
        this.sidebarFilter.setFilter(filter);
        this.modalFilter.setFilter(filter);
    }
}

我不确定是否可以编写更通用的版本 - 不依赖于特定的 FilterComponent 类型 - UnwrapFilter。 这是因为 infer 语句似乎要求 Textends 之后的任何内容的直接实例化,即在以下示例中,T1 被正确推断,但 {{ 1}} 不是。

T2

在其他情况下,可以使用 类型查询 - 现在在文档中称为 Indexed Access Types - 可以使用。

在此示例中,interface OneParamGeneric<T> {} type UnwrapOneParam<T extends OneParamGeneric<{}>> = T extends OneParamGeneric<infer TypeArg> ? TypeArg : never; type T1 = UnwrapOneParam<OneParamGeneric<TestFilter>>; type T2 = UnwrapOneParam<FilterComponent<TestFilter>>; PublicFilterComponent 公开为字段,从而允许通过方括号语法 activeFilter 进行访问。

PublicFilterComponent['activeFilter']