112022.5

Typescript从联合类型转化到交叉合并后的对象类型

我们有如下一个联合类型:

type union = { a: string } | { b: number } | { c: boolean }

如何得到最终的类型:

type obj = {
  a: string
  b: number
  c: boolean
}

如果是用js来写,不要太简单,但是typescript没有对union的遍历能力,所以只能走其他办法,经过探索后最终得到如下解:

type GetUnionKeys<Unoin> = Unoin extends any
  ? {
      [key in keyof Unoin]: key;
    } extends {
      [key in keyof Unoin]: infer K;
    }
    ? K
    : never
  : never;

type UnionToInterByKeys<Union, Keys extends string | number | symbol> = {
  [key in Keys]: Union extends any
    ? {
        [k in keyof Union]: k extends key ? Union[k] : never;
      } extends {
        [k in keyof Union]: infer P;
      }
      ? P
      : never
    : never;
};

type UnionToInter<Unoin> = UnionToInterByKeys<Unoin, GetUnionKeys<Unoin>>;

在使用时如下:

type obj = UnionToInter<union>

这样就可以实现我们的目的。我写了两个原子范型,GetUnionKeys用于获取联合类型里面的全部key,UnionToInterByKeys是关键,用于基于前面获得的keys再得到最后的对象。

不过这个方法存在一定的风险,假如联合类型中存在相同的属性,那么可能存在不确定性,比如:

type obj = UnionToInter<{ a: string, b: number } | { b: boolean }>

我们最终就会得到:

type obj = {
  a: string
  b: number | boolean
}

但是我们再开发中,常常会让后面一个覆盖前面的,我们期望得到的是:

type obj = {
  a: string
  b: boolean
}

我之前在读一些博客的时候,有同学提到可以通过冲载机制得到联合类型中的最后一个元素,但是我没有找到这篇文章,如果你看到,请在下方留言给我。

20:55:12 已有2条回复
  1. 深奥, 我只会合并两个, 这种批量的就完全不会了.
    type UnionZ<A> = {
    [k in (keyof A | keyof B)]: k extends keyof B ? B[k] : k extends keyof A ? A[k] : never;
    };
    #1195 1188 2022-05-17 11:30 回复
  2. #1209 千劫 2022-07-21 15:11 回复
102022.5

Nodejs检查端口是否占用,如果被占用使用一个随机端口

在日常开发中,我们常常要自己启动一个server来进行本地调试,但是如果写死端口,就会导致端口冲突,怎么解决呢?

/* eslint-disable @typescript-eslint/no-require-imports */
const net = require('net');

function checkPortUsable(port) {
  return new Promise((resolve, reject) => {
    const server = net.createConnection({ port });
    server.on('connect', () => {
      server.end();
      reject(`Port ${port} is not available!`);
    });
    server.on('error', () => {
      resolve(port);
    });
  });
}

function randomNumByRange(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function findUsablePort(port, minPort = 10000, maxPort = 65536) {
  const retry = () => {
    const port = randomNumByRange(minPort, maxPort);
    return findUsablePort(port, minPort, maxPort);
  };
  return checkPortUsable(port)
    .then(() => port)
    .catch(retry);
}

module.exports = {
  findUsablePort,
  checkPortUsable,
};

具体使用的时候,调用findUsablePort即可:

findUsablePort(4000).then((port) => app.listen(port))

如果4000可用,就会直接用4000,否则就会使用一个随机端口。

11:20:29 已有1条回复
  1. net.createConnection({ port })这种模式是建立客户端尝试连接该端口, 但是如果该端口已经被使用,但防火墙做了限制,应该也会触发连接错误; 会造成误判;
    用创建服务监听的方式应该更完善一些.
    #1220 躁动de气球 2022-08-31 17:33 回复