TypeScript:基于前一个类型保护参数

时间:2018-05-16 13:15:47

标签: typescript generics

我想实现函数参数的类型检查,其中第二个参数的属性基于前一个参数的属性。

config变量应仅包含values数组中对象中存在的此类属性。属性应该是可选的(不需要在config中包含所有属性,但不允许添加不同的属性。

请参阅示例代码:

type CustomType <T> = {
  [K in keyof T]: number
};
type Config <T> = {
  [K in keyof T]? : {
    highPriority: boolean;
    callback: (values: any[]) => number[];
  }
};

const customFunction = <T>(values: T[], config: Config <T> ): Array <CustomType<T>> => {
  // logic...

  return [];
};

const values = [
  {
    foo: 'foo',
    bar: 'bar'
  },
  {
    foo: 'foo',
    bar: 'bar'
  }
];

// Should optionaly contain only "foo", "bar" properties in this example
const config = {
  foo: {
    highPriority: true,
    callback: () => []
  },
  // not present in values objects
  wrong: {
    highPriority: true,
    callback: () => []
  }
};

// config should be marked with errors as "wrong" is not present in values objects
const result = customFunction(values, config);

在最后一行中,config应标记为错误,因为它会引入wrong属性,该属性在原始values对象中不存在。

我可以通过实现config的接口强制进行一些检查,但我认为这是不必要的,没有它就可以完成。

interface ISpecific {
  foo: any,
  bar: any
}

const values: ISpecific[] = [
  {
    foo: 'foo',
    bar: 'bar'
  },
  {
    foo: 'foo',
    bar: 'bar'
  }
];

const config: Config<ISpecific> = {
  // ...
  // wrong property is marked as error
}

更新:

  • config在其他地方定义,不了解values变量
  • customFunction用于整个应用程序的多个位置,因此将config作为对象文字传递是不可行的。

任何帮助?

1 个答案:

答案 0 :(得分:3)

如果将对象文字直接分配给给定类型的变量/参数,

Typescript仅检查多余属性,如文档here所述。在您的情况下,您可以显式键入config,或直接使用对象文字作为参数:

const values = [
    {
        foo: 'foo',
        bar: 'bar'
    },
    {
        foo: 'foo',
        bar: 'bar'
    }
];

// We type relative to values, no need for the extra interface
const config: Config<typeof values[number]> = {
    foo: {
        highPriority: true,
        callback: () => []
    },
    // will be an error
    wrong: {
        highPriority: true,
        callback: () => []
    }
};

//Or pass the object literal directly 
const result2 = customFunction(values, {
    foo: {
        highPriority: true,
        callback: () => []
    },
    // error
    wrong: {
        highPriority: true,
        callback: () => []
    }
});

另一种选择是使用条件类型和额外参数来触发错误,如果传递的类型具有额外的属性:

type NoExtraProperties<TSource, TTarget> = Exclude<keyof TSource, keyof TTarget> extends never ? true : "Extra properties detected";
const customFunction = <T, TConfig extends Config<T>>(values: T[], config: TConfig, validate: NoExtraProperties<TConfig, T>): Array<CustomType<T>> => {
    // logic...

    return [];
};

// Argument of type 'true' is not assignable to parameter of type '"Extra properties detected"'.
const result = customFunction(values, config, true); 

游乐场link