Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
TypeScript:数组中项的特定属性的并集_Typescript - Fatal编程技术网

TypeScript:数组中项的特定属性的并集

TypeScript:数组中项的特定属性的并集,typescript,Typescript,TLDR;版本 编辑,我添加了一个游乐场,链接在底部 我在TypeScript中有一个ob对象数组 interface Converter<T = Buffer> { name: string; uuid: CUUID; decode: (value: Buffer) => T; } const infoConverter: Converter<string> = { name: "info", uuid: "180a", decode:

TLDR;版本

编辑,我添加了一个游乐场,链接在底部

我在TypeScript中有一个ob对象数组

interface Converter<T = Buffer> {
  name: string;
  uuid: CUUID;
  decode: (value: Buffer) => T;
}

const infoConverter: Converter<string> = {
  name: "info",
  uuid: "180a",
  decode: v => v.toString()
};

const pressureConverter: Converter<number> = {
  name: "pressure",
  uuid: "1810",
  decode: v => v.readInt32BE(0)
};

type MyConverters = [Converter<string>, Converter<number>]

const converters: MyConverters = [infoConverter, pressureConverter];
以及对应于名称的泛型类型

type Value<Converters[], name extends string>
type Value<MyConverters, "pressure"> = number;
因此,现在,当有人想在外围设备上与
服务
通话时,他们应该能够将转换器传递到
服务
,现在可以通过名称寻址他们的
特征
,并在读取
特征
时获得解码值,而不是二进制数据,如下所示:

const infoConverter: Converter<string> = {
  name: "info",
  uuid: "180a",
  decode: v => v.toString()
};

const pressureConverter: Converter<number> = {
  name: "pressure",
  uuid: "1810",
  decode: v => v.readInt32BE(0)
};

const converters: Converters = [infoConverter, pressureConverter];

const service = new Service(converters);
const info = await service.read("info");
//    ^^^^                       ^^^^ 
//    this will be a string     their name instead of a UUID (like "a002")
应触发一个错误,说明这不是
转换器
数组中的名称。TypeScript还应该理解

const service = new Service(converters);
const info = await service.read("infoasdasd");
//    ^^^^
是一个字符串,因为您在
转换器中编写了内容

因为这一切看起来都很简单,我希望用户能够在没有
转换器的情况下工作。因此,如果他们创建了一个
服务
,而没有
转换器

const service = new Service();
const info = service.read("180a");
//    ^^^^                 ^^^^
//    Buffer               any CUUID (string | number)
它们应该能够传递任何特征UUID,并将获得一个缓冲区作为返回值。实施是有效的。我正在努力教
TypeScript
如何打字

到目前为止,我得到了这个:

type CUUID = number | string;

interface Converter<T = Buffer> {
  name: string;
  uuid: CUUID;
  decode: (value: Buffer) => T;
}

type Converters = Converter<any>[];
type NameOrCUUID<C> = C extends Converters ? Name<C> : CUUID;

type Name<C extends Converters> = "info" | "pressure";
type Value<C, N extends NameOrCUUID<C>> = "" | Buffer;

class Service<C> {
  private converters?: Converters;

  constructor(converters?: C) {
    this.converters = converters as any; // Ask on StackOverflow
  }

  public read<N extends NameOrCUUID<C>>(name: N): Value<C, N> {
    if (this.converters) {
      return this.getConvertedValue(name);
    } else {
      return this.getBufferForUUID(name);
    }
  }

  private getBufferForUUID(uuid: CUUID): Buffer {
    return Buffer.from("Foobar", "utf8"); // Dummy Code
  }

  private getConvertedValue<N extends NameOrCUUID<C>>(name: N): Value<C, N> {
    return "Foobar"; // Dummy Code
  }
}
然后将
转换器
作为一个参数传递到上面,它会告诉我只能传递
信息
压力
。我根本不通过任何转换器(
service2
),我可以通过任何数字或字符串

但这只是假的,因为

type Name<C extends Converters> = "???";
type Value<C, N extends NameOrCUUID<C>> = "???";
type Name=“?”;
类型值=“???”;
对于这个,这个,这是我无法理解的部分

我需要告诉
TypeScript
以允许
Converters
中任何项的
name
属性与值类似,并且值必须与名称匹配

好的,对不起,这是文字墙。我希望我能表达我的问题(最后一段才是真正的问题)。我想知道这在打字脚本中是否可行

interface Converter<T = Buffer> {
  name: string;
  uuid: CUUID;
  decode: (value: Buffer) => T;
}

const infoConverter: Converter<string> = {
  name: "info",
  uuid: "180a",
  decode: v => v.toString()
};

const pressureConverter: Converter<number> = {
  name: "pressure",
  uuid: "1810",
  decode: v => v.readInt32BE(0)
};

type MyConverters = [Converter<string>, Converter<number>]

const converters: MyConverters = [infoConverter, pressureConverter];
这里是一个游乐场:


我看到的第一个问题是
infoConverter
作为
Converter
pressureConverter
作为
Converter
的类型注释太宽。编译器将尽职尽责地忘记
infoConverter.name
“info”
,而是使用表示它是
字符串的类型注释

我认为,只要使用类型推断和a来为转换器实例获取尽可能狭窄的类型,您就会更接近您想要的:

const infoConverter = {
  name: "info",
  uuid: "180a",
  decode: (v: Buffer) => v.toString()
} as const;

const pressureConverter = {
  name: "pressure",
  uuid: "1810",
  decode: (v: Buffer) => v / 1024
} as const;

const converters = [infoConverter, pressureConverter] as const;

此时,不能保证
转换器的元素符合
转换器
接口,但您可以确保任何接受
转换器
的函数或接受
类型转换器
的类型都被约束为
转换器

“tuple”可能是此处添加的一个好关键字(即
MyConverters
是什么)我有一个问题。我理解为什么
const
赋值是必要的,但当我把它注释出来时,它仍然有效。我不明白,因为你说的完全有道理!无法发布链接,因为url太长,但如果你这样做
const converters=[infoConverter,pressureConverter];//作为常量;
在第22行它仍然有效。
infoConverter
pressureConverter
定义中的
const
断言非常有用,因为没有它们,您需要其他方法来确保
的“信息”
的“压力”
名称不会变宽。但是一旦
infoConverter
pressureConverter
已经变窄,您确实不需要在
Converter
定义中使用
const
断言,因为所做的只是保留两个条目的顺序,而您的代码并不真正关心这一点。我不会说
as const
是必要的;这只是缩小推论范围的最方便的方法之一。非常感谢您的解释,您是一个传奇!
const service = new Service(converters);
const info = service.read("info");

const service2 = new Service();
const info2 = service2.read("180a");
type Name<C extends Converters> = "???";
type Value<C, N extends NameOrCUUID<C>> = "???";
const infoConverter = {
  name: "info",
  uuid: "180a",
  decode: (v: Buffer) => v.toString()
} as const;

const pressureConverter = {
  name: "pressure",
  uuid: "1810",
  decode: (v: Buffer) => v / 1024
} as const;

const converters = [infoConverter, pressureConverter] as const;
type Names<C extends ReadonlyArray<Converter<any>>> = C[number]["name"];

type Value<
  C extends ReadonlyArray<Converter<any>>,
  N extends Names<C>
> = Extract<C[number], { name: N }> extends Converter<infer V> ? V : never;
type TheNames = Names<typeof converters>; // "info" | "pressure"
type InfoValue = Value<typeof converters, "info">; // string
type PressureValue = Value<typeof converters, "pressure">; // number