实际开发中我需要用到太多的键值对,并且有相当一部分情况下,键名是一个联合,而且还是某个数组的联合,然而早期 TS 对这样的联合实现并不是很理想。

这几天又翻了翻 Stack Overflow,发现很多新答案,对此整理一下。

后面的内容最主要的是针对 TS 增加了 字面量常量上下文表达式(Const contexts for literal expressions) 而展开的,所以需了解下它,为了简化,后面简称为 常量字面量。

常量字面量确定了一个对象或数组的所有子级是只读的,也就是不可修改。

比如声明一个常量:

const obj = {
  foo: "one",
  bar: "aaa",

默认情况下,这个对象的类型如下:

type Obj = {
  foo: string;
  bar: string;

因为常量是只读的,所以一般会这么做:

type Obj = Readonly<{
  foo: "one";
  bar: "aaa";
const obj: Obj = {
  foo: "one",
  bar: "aaa",

重复再写一遍,累死个人啦。

TS 把上面的这种完全常量的类型断言为常量字面量,可以使用 const 关键字来断言,比如:

const obj = <const>{
  foo: "one",
  bar: "aaa",
// or
const obj2 = {
  foo: "one",
  bar: "aaa",
} as const;

上面两种方式都可以把对象或者数组断言为常量字面量。

对象或者数组通过断言为常量字面量后,所有内部属性都是只读的,上面的类型为:

const obj: {
  readonly foo: "one";
  readonly bar: "aaa";

这个东西和联合有什么关系?

因为这些数据都是只读的,所以这些对象或者数组的值都会被定义为字面量,就比如:

// type is : string[]
const arr = ["foo", "bar", "baz"];
// type is : readonly ["foo", "bar", "baz"]
const arr2 = ["foo", "bar", "baz"] as const;

上面的代码中, arr 的类型是 string[],但是 arr2 的类型就变为了一个只读元组 readonly ["foo", "bar", "baz"],此时它的值是常量,并且元组本身只读。

好玩的来了,那么拿这个只读元组的值作为类型如何,比如:

const arr2 = ["foo", "bar", "baz"] as const;
// type is : "foo" | "bar" | "baz"
type Values = typeof arr2[number];

此时 Values 的类型将会成为只读元组 arr2 的值的联合。

接下来分析下常量字面量断言的应用。

使用字符串数组的值创建联合

比如现在有一个字符串数组如下:

const arr = ["foo", "bar", "baz"];
//现在我们需要根据数组的值来创建一个这样的联合:
type Keys = "foo" | "bar" | "baz";

可以这样定义这个联合:

const arr = <const>["foo", "bar", "baz"];
type Keys = typeof arr[number];

使用对象的键创建联合

使用对象的键创建联合:

const obj = {
  foo: 1,
  bar: 2,
  baz: 3,
} as const;
// 同上一节需要得到使用键名生成的联合,那么可以这样编写类型:
// type si : "foo" | "bar" | "baz";
type Keys = keyof typeof obj;

使用对象的值作为联合

有时候我们希望把对象的值作为一个联合,可以使用以下方法:

const obj = {
  k1: "foo",
  k2: "bar",
  k3: "baz",
} as const;
// type Keys = "foo" | "bar" | "baz"
type Keys = typeof obj[keyof typeof obj];

还有的特殊情况是辨识联合,比如一个对象数组如下

const objs = [
  { name: "foo", other: "something" },
  { name: "bar", other: "something" },
  { name: "baz", other: "something" },

此时我们需要使用这个对象数组中每项的 name 创建一个联合,那么可以这样实现:

const objs = [
  { name: "foo", other: "something" },
  { name: "bar", other: "something" },
  { name: "baz", other: "something" },
] as const;
// type Keys = "foo" | "bar" | "baz"
type Keys = typeof objs[number]["name"];

使用联合作为对象的键名

有时候需要反向操作,把一个联合作为一个对象的键名,比如以下需求:

const keys = ["foo", "bar", "baz"];
const obj = {};
keys.forEach((v) => (obj[v] = true));

此时 obj 的类型是 string[],这明显不是我们预期的,因为程序运行结束 obj 的键名都是由 keys 数组的值映射的。

不过可以使用以下方式解决这个问题:

const keys = ["foo", "bar", "baz"] as const;
const obj: {
  [index in typeof keys[number]]?: boolean;
} = {};
keys.forEach((v) => (obj[v] = true));
// 此时 `obj` 的类型为:
// const obj: {
//   foo?: boolean;
//   bar?: boolean;
//   baz?: boolean;
// };

Convert array of strings to TypeScript type

Typescript: derive union type from array of objects

Typescript derive union type from tuple/array values

前言实际开发中我需要用到太多的键值对,并且有相当一部分情况下,键名是一个联合,而且还是某个数组的联合,然而早期 TS 对这样的联合实现并不是很理想。这几天又翻了翻 Stack Overflow,发现很多新答案,对此整理一下。后面的内容最主要的是针对 TS 增加了 字面量常量上下文表达式(Const contexts for literal expressions) 而展开的,所以需了解下它,为了简化,后面简称为 常量字面量。常量字面量确定了一个对象或数组的所有子级是只读的,也就是不可修改。比如声明
const keys: any[] = Object.keys(reqOfAClient); keys.forEach(key => { console.log(key + ":" + key.value); 本软件在许可下提供,但仅提供用于非商业目的。 本软件及本软件所使用的有一些网上代码及资源以研究或个人/学习交流为目的,声称原公司(作者)允许不要使用任何商业用途,如需商业请自行联系原公司(作者) )商议商用方案!不要擅自私自商用!否则后果自负! 本软件及作者不承担因使用,分发,再开发等所带来的替代或其他法律责任。 本软件总体只在Win10 20H2 x64测试运行过,理论上可以运行在Linux或Mac OS上,但未测试 安装node.js 推荐安装node-v15.4.0-x64.msi 安装cnpm 输入以下命令 npm install -g cnpm --registry=https://registry.npm.taobao.org 输入cnpm -v输入是否正常 cnpm -v 解决cnpm报错 如果报错:无法加载文件%AppData%\ Roa
如果有 10 个、100 个这种方式就变的很不实用,这时我们可以使用数组来解决: var sites:string[]; sites = ["Google","Runoob","Taobao"] 这样看起来就简洁多了。 TypeScript 声明数组的语法格式如下所示: var array_name[:datat 将javascript对象中的键转换为特定样式(camelCase,snake_case等) $ npm install --save @ridi/object-case-converter import { camelize , decamelize } from '@ridi/object-case-converter' ; const result1 = camelize ( null ) ; // result1 = null const result2 = camelize ( { id : '1' , nick_name : 'nick1' , contacts : [ { contact_type : 'phone' , value : '000-000-000' } , { contact_type : 'em
1.介绍typeScript是微软推出的一款能支持es6语法的javascript语言,能支持类型检测,语法提示,重构,也是angular2的开发语言。2.语法2.1字符型 (1)多行字符串 let a = `1111 2222`等价于var a = "111\n3333\n112222";(2)字符串模板 可以直接添加变量 无需+连接let name = 'zw' let a = `My
TypeScript-学不会的ts-1TypeScript 是什么?如何安装TS编译TS变量声明TypeScript 变量的命名规则:变量的声明数据类型Boolean类型Number类型String类型Array类型Enum枚举类型Any 类型Map对象创建Mapmap.clear()map.set()map.get()map.has()map.delete()map.sizemap.keys()map.values() TypeScript 是什么? TypeScript 是一种由微软开发的自由和开源的编
const strArray: string[] = ['foo', 'bar', 'baz']; for (let i = 0; i < strArray.length; i++) { console.log(strArray[i]); 使用 forEach 方法: ```typescript const strArray: string[] = ['foo', 'bar', 'baz']; strArray.forEach((str: string) => { console.log(str); 这两种方式都能够遍历字符串数组中的每一个元素,并输出到控制台中。需要注意的是,在 TypeScript 中,需要显式指定数组中元素的类型玄晓乌屋: 我并没有使用过 Bun。Bun 现在还很年轻,从速度上,它肯定能吊打 Node 和 Deno,但是现在它的生态还不够完善,使用的库也是 node package,目前不推荐生产环境使用。 同时 Bun 现在也不是 Node 的超集,更不完全兼容 Deno。你不用过分关注 Bun,以前没有 v8 的时候,各个厂家的 javascript 运行时也是五花八门,总归来说它们都是按照 es 标准去设计的,把代码迁移到 Bun 并不会对业务层代码进行大面积改动。 vue 自定义组件双向数据绑定 CSDN-Ada助手: Bun 号称吊打 Node 和 Deno,你有试用过么? js 中使用 encodeURI 把 svg 转 base64 玄晓乌屋: 元素不行,你看参数,只接受 svg 字符串 js 中使用 encodeURI 把 svg 转 base64 tutouxue1: svg标签也可以么 vue-cli cdn方式引入Vue模块 old-handsome: