【问题标题】:enforcing function's parameter must belongs to generic type T强制函数的参数必须属于泛型类型 T
【发布时间】:2018-08-27 07:12:32
【问题描述】:

在我的打字稿函数中,我想强制第二个参数的所有键必须属于第一个参数的对象。

类似的东西

mapTo([new KeyValue('a', 'b'), new KeyValue('x', 'y')], {key: {key2: 1}});

在此第二个参数的所有键(keykey2)必须属于 KeyValue 对象的键

这里的 KeyValue 是:

class KeyValue {
  key: string;
  key2: string;

  constructor(k, k2) {
    this.key = k;
    this.key2 = k2;
  }
}

喜欢

mapTo([new KeyValue('a', 'b')], {key: {key2: 1}}); -> 好的

mapTo([new KeyValue('a', 'b')], {key: {key3: 1}}); -> 错误 // 无效的 key3

为此我实现了 mapTo 功能

public nest<T, K extends keyof T, K2 extends keyof T>(arr: [T], basis: {[k in K]: {[k2 in K2]}}) {
    console.log('Hello!!!');
    console.log(basis);
  }

这段代码工作完美,但如果我在 KeyValue 类中添加另一个键并在参数中传递这个键,如下所示:

mapTo([new KeyValue('a', 'b' ,'c')], {key: {key2: {key3: 1}}});

和 KeyValue 到:

class KeyValue {
  key: string;
  key2: string;
  key3: string;

  constructor(k, k2, k3) {
    this.key = k;
    this.key2 = k2; 
    this.key2 = k3;
  }
}

那么我上面实现的函数不会验证第三个键

那么我怎样才能实现上述功能,以便它接受动态嵌套值并完美地工作。

更多示例:

mapTo([new KeyValue('a', 'b' ,'c')], {key: 1}); -> 好的

mapTo([new KeyValue('a', 'b' ,'c')], {key: {key1:1}}); -> 好的

mapTo([new KeyValue('a', 'b' ,'c')], {key1: {key:1}}); -> 好的

mapTo([new KeyValue('a', 'b' ,'c')], {key1: {key:{key3:1}}}); -> 好的

mapTo([new KeyValue('a', 'b' ,'c')], {key1: {key:{key4:1}}}); -> 错误 // key4 不存在

mapTo([new KeyValue('a', 'b' ,'c')], {key3: {key2:0}); -> 好的

【问题讨论】:

  • 如果有 3 个键,调用者是否必须指定 3 级嵌套结构?你的例子是{key : 1} 有效吗?还是必须是{key : {key2 : {key3 : 0 }}
  • 不是强制性的,但来电者可以使用 2 或 3 个键来呼叫。喜欢:mapTo([new KeyValue('a', 'b' ,'c')], {key: 1}); -&gt; okay mapTo([new KeyValue('a', 'b' ,'c')], {key: {key1:1}}); -&gt; okay mapTo([new KeyValue('a', 'b' ,'c')], {key1: {key:1}}); -&gt; okay mapTo([new KeyValue('a', 'b' ,'c')], {key1: {key:{key3:1}}}); -&gt; okay mapTo([new KeyValue('a', 'b' ,'c')], {key1: {key:{key4:1}}}); -&gt; error // key4 not exist
  • 我认为您的示例有错误.. key1 来自哪里?

标签: javascript typescript generics


【解决方案1】:

您可以使用递归映射类型来定义一个结构,该结构允许在每个级别指定T 的任何键。我们还可以通过使用Omit 类型省略每个级别上的当前键来确保在路径中没有指定键两次:

type Diff<T extends string, U extends string> = ({ [P in T]: P } & { [P in U]: never } & { [x: string]: never })[T];
type Omit<T, K extends keyof T> = Pick<T, Diff<keyof T, K>>;


type Nested<T> = { [P in keyof T]?: Nested<Omit<T, P>> | number }


function mapTo<T>(arr: [T], basis: Nested<T>) {
    console.log('Hello!!!');
    console.log(basis);
}
class KeyValue {
    constructor(public key: string, public key1: string, public key3: string) {
    }
}

mapTo([new KeyValue('a', 'b', 'c')], { key: 1 }); //-> okay 
mapTo([new KeyValue('a', 'b', 'c')], { key: { key1: 1 } }); //-> okay 
mapTo([new KeyValue('a', 'b', 'c')], { key1: { key: 1 } }); //-> okay 
mapTo([new KeyValue('a', 'b', 'c')], { key1: { key: { key3: 1 } } }); //-> okay
mapTo([new KeyValue('a', 'b', 'c')], { key1: { key: { key4: 1 } } }); //-> error // key4 not exist
mapTo([new KeyValue('a', 'b', 'c')], { key: { key: 1 } }); //-> error, key appears twice 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-19
    • 2015-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-27
    相关资源
    最近更新 更多