当A和O都是对象的属性时,使用字符串数组A的值作为对象O中的键 [英] Use values of string array A as keys in object O when A and O are both properties of an object

查看:0
本文介绍了当A和O都是对象的属性时,使用字符串数组A的值作为对象O中的键的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个类型,它是一个对象,具有属性valuesvaluesMapvalues应为字符串数组,valuesMap应为对象,键为values中的条目,值为字符串或布尔值。我正在努力在TypeScrip中定义这个类型约束。以下是我尝试过的方法:

type FilterOptionBase<K extends string> = {
  name: string;
  values: K[];
  multiselect: boolean;
  isBoolean?: boolean;
  valuesMap?: {
    [key in K]: string | boolean;
  };
};

type FilterOption = FilterOptionBase<string>

const myBadFilter: FilterOption = {
    name: 'Status',
    values: ["Online", "Offline"],
    multiselect: false,
    valuesMap: {
        Online: true,
        NotSure: false // <------ should error but doesnt
    }
}

TypeScript playground

我觉得这应该是相对简单的,但我想不到解决方案。如果以前有人问过这个问题,请指引我去正确的地方!

同时:

如果isBoolean定义为true,我们是否也可以将valueMap的值扭曲为布尔值,而不是boolean | string

推荐答案

您的示例不起作用的原因是:

type FilterOption = FilterOptionBase<string>

...正在将string传递到FilterOptionBase,实质上是这样做的:

type FilterOptionBase = {
  name: string;
  values: string[];
  multiselect: boolean;
  isBoolean?: boolean;
  valuesMap?: {
    [key in string]: string | boolean;
  };
};

因此,要正确键入该类型,您需要传入使用该类型时所需的字符串列表,如下所示:

const myBadFilter: FilterOptionBase<"Online" | "Offline"> = {
  name: 'Status',
  values: ["Online", "Offline"],
  multiselect: false,
  valuesMap: {
      Online: true,
      NotSure: false // <------ errors now!
  }
}

然而,我认为实际上试图做的是将FilterOptionBase类型用作各种不同对象的模板,不幸的是,没有办法这样做。您的类型不能同时从自身读取约束自身。

但是您可以访问传递给函数的对象上的值,所以这里有一个我过去用过的解决办法,效果很好:

const filterFactory = <K extends string>(v: FilterOptionBase<K>) => v

const myBadFilter = filterFactory({
  name: 'Status',
  values: ['Online', 'Offline'],
  multiselect: false,
  valuesMap: {
    Online: true, 
    NotSure: false, // <------ it's an error!
  }
})

&另请回答

可以,可以根据isBooleantrue进行更改。您只需要做一个联合:

type foo = {
  isBoolean: true
  value: boolean
} | {
  isBoolean: false
  value: string
}

尽管它确实变得有点棘手,因为您必须使用工厂函数来解决这个问题。这就是:

type FilterOptionBase<
  K extends string,
  B extends boolean | undefined,
> = B extends true
  ? {
      name: string
      values: K[]
      multiselect: boolean
      isBoolean: B
      valuesMap?: {
        [key in K]: boolean
      }
    }
  : {
      name: string
      values: K[]
      multiselect: boolean
      isBoolean?: B
      valuesMap?: {
        [key in K]: string
      }
    }

const filterFactory = <K extends string, B extends boolean | undefined>(
  v: FilterOptionBase<K, B>,
) => v

const myBadFilter = filterFactory({
  name: "Status",
  values: ["Online", "Offline"],
  multiselect: false,
  isBoolean: true,
  valuesMap: {
    Online: true,
    Offline: "foo", // <------ also an error!
  },
})

const myOtherBadFilter = filterFactory({
  name: "Status",
  values: ["Online", "Offline"],
  multiselect: false,
  isBoolean: false,
  valuesMap: {
    Online: true, // <------ also an error!
    Offline: "foo",
  },
})

这篇关于当A和O都是对象的属性时,使用字符串数组A的值作为对象O中的键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆