首页 > 解决方案 > 对于对象键中的条件类型,如何删除某些键以生成子对象类型?

问题描述

这是我使用一些高级类型的方法。我想创建一个扩展 BaseConfig 的配置类型。使用此配置类型,与具有在配置类型中标记为“是”相同的属性的 dataProducer 类型(在示例中命名为 Conf)之间。

interface BaseConfig1 {
    a: 'yes'|'no';
    b: 'yes'|'no';
}

interface BaseConfig2 {
    a?: 'yes';
    b?: 'yes';
}

interface Config1 extends BaseConfig1 {
    a: 'yes';
}

interface Config2 extends BaseConfig2 {
    a: 'yes';
}


type Conf<T, D> = {
    [P in keyof T]: T[P] extends 'yes'? ((data:D) => string): never;
};

// Error. Missing property b.
const dataProducer1: Conf<Config1, any> = {a: (data:any) => ''};

// Works
const dataProducer2: Conf<Config2, any> = {a: (data:any) => ''};

理想情况下,BaseConfig1 是我真正想要定义的。您需要在子类型中标记“是”来配置输出类型。但是 TS 坚持让我提供类型为 never 的 ab 属性。不应该像 Filter 类型那样在类型中被排除在外吗? type Filter<T, U> = T extends U ? T : never;

我能做的最好的是BaseConfig2,有更好的主意吗?

更新:我确实想强制结果类型将属性标记为“是”类型。对于上面的示例,结果类型应具有“a”属性。

更新 2:另一个问题,对于 BaseConfig2,b 的类型是 'yes'|undefined,那么为什么Conf<Config2, any>期望具有未定义类型的可选 b 属性而不是从未类型的 ab。

更新 3:尝试了另一种定义 Conf 的方法,但不起作用。

type Conf<T, D> = {
    [P in keyof T & T[P] extends 'yes']: (data:D) => string;
};

标签: typescripttypescript-typings

解决方案


interface BaseConfig {
  a: 'yes'|'no';
  b: 'yes'|'no';
}

interface BaseConfigD {
  a: (data:any) => string;
  b: (data:any) => string;
}

interface Config extends BaseConfig {
  a: 'yes';
}

// Extract the property names that extend 'yes'
type ConfProps<T> = {
  [P in keyof T]: T[P] extends 'yes'? P: never;
}[keyof T];

// Properties of Config that extend 'yes'
type ConfigProps = ConfProps<Config>;

// Properties of BaseConfigD that extend 'yes' from Config..
type BaseConfigDBasedOnConfigProps = Pick<BaseConfigD, ConfigProps>;

const dataProducer1: BaseConfigDBasedOnConfigProps = {a: (data:any) => ''};

推荐阅读