如何使用typeof获取对象的“运行时”类型?

时间:2019-02-20 11:29:11

标签: typescript

我想获取具有已声明键/值的对象类型。 我有以下代码:

interface ConfigVar<T extends 'string' | 'number' | 'boolean'> {
  env: string;
  type: T;
}

interface ConfigMap {
  [key: string]: ConfigVar<'string'> | ConfigVar<'number'> | ConfigVar<'boolean'>;
}

type ConfigType<T extends ConfigMap> = {
  [P in Extract<keyof T, string>]:
    T[P] extends ConfigVar<'string'> ? string :
    T[P] extends ConfigVar<'boolean'> ? boolean :
    T[P] extends ConfigVar<'number'> ? number :
    never;
};

// usage

const configMap: ConfigMap = {
  var1: {
    env: 'VAR1',
    type: 'string',
  },
};

type ConfigMapType = ConfigType<typeof configMap>;

const config: ConfigMapType = {
  var1: true, // Type 'boolean' is not assignable to type 'never'
  // var1: 'str', // Type 'string' is not assignable to type 'never'
};

我的目标是使ConfigMapType仅允许{ var1: string }。打字稿可以吗?

2 个答案:

答案 0 :(得分:1)

您的条件类型还可以,您唯一的问题就是保留configMap的实际类型。如果您有一个显式类型注释,它将成为变量的最终类型,并且对象文字的类型将不起作用。同时保留约束和从对象文字推断类型的最佳方法是使用泛型函数:

interface ConfigVar<T extends 'string' | 'number' | 'boolean'> {
  env: string;
  type: T;
}

interface ConfigMap {
  [key: string]: ConfigVar<'string'> | ConfigVar<'number'> | ConfigVar<'boolean'>;
}

type ConfigType<T extends ConfigMap> = {
  [P in Extract<keyof T, string>]:
    T[P] extends ConfigVar<'string'> ? string :
    T[P] extends ConfigVar<'boolean'> ? boolean :
    T[P] extends ConfigVar<'number'> ? number :
    never;
};

// usage

const configMap = (<T extends ConfigMap>(o:T)=> o)({
  var1: {
    env: 'VAR1',
    type: 'string',
  },
});

type ConfigMapType = ConfigType<typeof configMap>;

const config: ConfigMapType = {

  var1: 'str
};

答案 1 :(得分:1)

configMapvar1都是值,而不是类型。因此,TypeScript无法对其进行验证。您需要将var1放在类型定义之一中,例如:

type ConfigMapType = ConfigType<{ var1: ConfigVar<'string'> }>;

interface ConfigVar<T extends 'string' | 'number' | 'boolean' = 'string'> {
    env: string;
    type: T;
}

type ConfigType<T> = {
    [P in Extract<keyof T, string>]:
    T[P] extends ConfigVar<'string'> ? string :
    T[P] extends ConfigVar<'boolean'> ? boolean :
    T[P] extends ConfigVar<'number'> ? number :
    never;
};

const configMap = {
    var1: <ConfigVar>{
        env: 'VAR1',
        type: 'string',
    },
};

type ConfigMapType = ConfigType<typeof configMap>;

const config: ConfigMapType = {
    var1: 'string',
};