类型缩小

假设我们有一个名为 padLeft 的函数。

function padLeft(padding: number | string, input: string): string {
  throw new Error("Not implemented yet!");
}

如果 paddingnumber,它会将其视为我们想要添加到 input 的空格数。如果 paddingstring,它应该只是将 padding 前置到 input。让我们尝试实现当 padLeftpadding 传递 number 时的逻辑。

function padLeft(padding: number | string, input: string) {
  return " ".repeat(padding) + input;
}

哦,我们在 padding 上遇到错误。TypeScript 警告我们,将 number | string 添加到 number 可能不会给我们想要的东西,这是正确的。换句话说,我们没有先明确检查 padding 是否是 number,也没有处理它是 string 的情况,所以让我们这样做。

function padLeft(padding: number | string, input: string) {
  if (typeof padding === "number") {
    return " ".repeat(padding) + input;
  }
  return padding + input;
}

如果这看起来像是无趣的 JavaScript 代码,那就是重点。除了我们放置的注释之外,这个 TypeScript 代码看起来像 JavaScript。这个想法是 TypeScript 的类型系统旨在使编写典型的 JavaScript 代码尽可能容易,而无需向后弯腰以获得类型安全。

虽然它可能看起来不多,但实际上这里有很多东西。就像 TypeScript 如何使用静态类型分析运行时值一样,它在 JavaScript 的运行时控制流结构(如 if/else、条件三元组、循环、真实性检查等)上进行类型分析,这些都会影响这些类型。

c6sF3Ru5kT8XQjhbbAqD5746KicNavI+u/q1ZaNDH5RA+zNONZ38so/ej5das/dW5xDCH5VS52KB7YH+KetjIiHmiLdoWeEvlBDgCzB2JzEO5ddTxqu4j5zLgOBrMlzPVRdJLBRobdSLeO5/iJnyduCqalmw7LAB8bwLdJPkINTJ+jYUHHa67OiGgZ6TUlT931vX1AMDFhL7ucEu3gk2zhdHFrNVg7vbH68bSNOWK/Dbvm5EIVlLaT55O+Ok/4ajyTS+8/iwTdfTPU6+7ZT8sX79hup8U/4eU7R6HAXH6xnIg8qfwzUCub++tRUGf+UEHhUII0gnfp9OH7Tyh6R/fCib3FfgSwV6dR0JUGrPxH7Cl+9USCBLZLE8vhPAn0wVnONVofk8Y6kGRSWj8TaidhzFwZScNwfdQ2Ve2mQ/keerU+QLaJzAnH71KH3Tfir3y+WbVw5GftmdbHIlbw1rm4LsiSG7e3Oon+3n9scIKDQ4Qe2nyRqqxua+zc4Rl+HR6wtKjAPUQjyvxrNBXA09/1z+chvQZbbtcx5eK5gohfT0SmGgCr35P1oY7Gi8W51q2ZYBcuZg9TEksVktNgLiej8PcX4A/IF+h8FquA2CQwcAjb5n+oV1mKMgLiEE84h5C/hh22SIFpAQLu6l1gMh72Fv2lMxJufjrQSmU6FHYC9O8bs23A+G8gOcKBXbnxp5r1BKZBk34dlBzkSXj1uxHw==

function padLeft(padding: number | string, input: string) {
  if (typeof padding === "number") {
    return " ".repeat(padding) + input;
  }
  return padding + input;
}

9pmqv2JMhgqw7ZYgTZ7NZfb5tS39/UAvq8QydSB9HcwJ+1py4pPlKvVnmAZtnNeHodNQoCniLdJ1acKrfeVc+BFI0ybS+liEQsCfHtA1XQo=

typeof 类型保护

Z/SQOd/ReMcLw46TBxBTMmdeyPff7HvvzEnQGCLMbz5xJM/EQR16mOKXQ4kUYz+XXG1H/dSpLa44XOEfhOuqm166aAZN2t2tgZgaW93Vtm207MQelgAzHhGUzPF+nNgGLKCc72DTq38QMTH1WL1FtW93FzelZpsb8JoFXwTA4zdmyFSeJMt7pPcgBzBM51Gf6pGuuYh12808BjLke6zX+McchWgqhtINoqAmuOrwGWFMk5d2dwUVhaB2y43HuClBWKFqcTxCj95+4nt7FzmMO+q1XnQurprmYS0aSJ0Tyrc=

    kZBnw6W1+qMhuscZogABUkbfmKqoaKeX5PQSpiT8y74S0rcbN2LZAN4CNwMsKCAK8pycs/OmwXxgY7qAAMKr+EsROLRnjYiaXRiIWnfk4+4UK4Y2d+3tJs5D9OxjgEJJi70msKKTOlLrxq6SuaiVr8z4pO1d/wfKMb6TAoXx060KVfr+6j71bp1jF9MoV6L46f2lobNy/bOigc5CsHaQI69Mp23mhzSE6KymNv7xpK/xhaF33+j/IlXVH5pV/2N7ONBpQVpTYl1ACZH8vO+L2fVn/xbzmAL4wcdodTxFKP8Qf/HqOHhYJ7a5kR+LuzdKubPaoaNqv+ANYStFL094cw==

4Lnvg4QB6vUJwrfQ4r2eZtp9YTvLOuQsNsWsUxu4ObYg97PEqj4aO5IAuf1wMsa4R6EenmKwty9VHHyztCWM96vzZV+vOllsyFhvyORgPaNOg52aDpecKw2v2LI7/GF8cyhLYHpP8O134eDyS28tUpp3S2T4XKkHAVNBpxWITZdZwwcN8vWTVhnkirh7E53d+UOKr5I+mf5PGzzBZ7Jw+ueDu1S3ZE6YniqivT/uZP/HIreT/ONv46bhp8hW16Z0

P99Wfj6gXtyqrISLMgiBJCyqjbQ1/9SeVj3Dk4KcZZgUchtRb25yNO4+dMIA1jd+oSrSlqTqABnZFxs31RuHEzwZae1QB6EJHARm5ZDSgmXVPO2nEDvxI+W8XZWypKhxkB+xRBMDjeDnMLTFSoecItnIIKyKaCgc4xp/XFX4EjTgyWjRbfXOW77+d8OWYc79xFg53nNAkCmtp7Q5HxsAz/t6HNOP6s9kDC3lWngmNrX+bsDqqLbB5CjX6FNAmTaiathmNBQlZykI/7S0DRx2qvy9RcPQqTVaxK8fcBYwVVl/SiXzFIG+v6FhVHT1r0T/zP8lMFL3vs2jXUE8D8YNX6y2dSE/Q1FLWwrYfeWRFMS8gSf8kIYrGCiJYnxGLQR0cTZ5Q3l/XzLfBTfY47M3RUVw+THz3Ch0zpepgdj4rs2gwD9568yPJ8HqfMJpU8TsU2w0OwrdSP7LvgCmLW34XA==

function printAll(strs: string | string[] | null) {
  if (typeof strs === "object") {
    for (const s of strs) {
      console.log(s);
    }
  } else if (typeof strs === "string") {
    console.log(strs);
  } else {
    // do nothing
  }
}

RxFfQ4H9CcsH+VPJ302/M2cmF6/N4IZG9+5xvqfJQZGpVnh21chWgZ+ABkppJjG22LwVE0TvXViPJmGFqMUtxeSYo9Pj2iEjQu8KbEtFKOpdWXpFeIAA31lmOrbaHq8ukCul2RRfMDf0g8uKt4DKLPLWPjfz2+8rK4Ee9fn/F9+6tY5zwYOK4S0+RKoEJtQnn5Rib+COl7oQlmA+nKCuPj9SuwZHFPx6BG7w9LGFKLZBZg81w9BmeJJobG54Za/EyG1ijI5XZL3UlA5YIJEIjnCWuWz2gRFrP7qQI2n/UZeFzKfiwqayagSw/2tP5EkGVDBxfeHOrrs6AKIU+8GrTt+Lq8evpqUxlGxLkdBe29XTqEWQ3/66JSyVOfx0jHFCFb26xFhy1qeTIsjCz1LENqjemLF237UY32SGCPjo7g/C9C24seSf8DHAMzqAuKkQ5AwKOJocjvUJZhIpUeiNUQ==

zr8J4cJiG0mltkNhjUeEjMBgYXu2DoA9CIEqChm3YLYV0Ny76aCx9Xi38AeA3a7MUvWXBTQBMQbdqCUw2z3k9oktcV8NAVf91UbGuO0ES6HSICWC2KM3JmQwzJy160kmSXsXpAj2E7zSPUNxUGf5nFp6RfSDMzzc7/1oiJf8B/yY3slM0kr31Z1wzro2rvoHwYE4FVwwbWKd4ldq/XMg7Y/wgl+HS15ZBl8PGfTGdxMNKDo9twyHEHbHc8Qe2/fs25uttuI9v7Bv50PR+b3Wuef2w/GreuCh4YcraywM9Vv9iJJTwQWuAIYCepxsnVqeFtGC6xejRVpEkmEUK1/bQfMdkpkBOdsqkBmXxqg/wHY=

rU7plhpfuUKLGj37tO8fgx9W5kfkC1XvVdFuwIriNUATWkFnOcZd68B+6z5jmZgpfMbnMWFRalaGs0e1GHQHqqV3bLd/4X94TQXul0vqfXs=

真实性缩小

UB6mQZvfYGcDTMag4a/QJi7ESZz/xjOfsnHa2+8QlbUnvKXJtfZcGs7EKPSbIwNx6C6WyLcn8QCnIHZnliHH2XOETvG/WCDabpx4K1wI4zI19zEgIsTIgObuIKAU9lg8hMOo9ZRGAOOMyzxF6d5Scw==

ItOVzsjrqb4bHT/FDu3JJmvrY5htqoIstBhJSw27m/LanoM883ZzmxMFmSZJWfvmeu0zwASFQ5Qfocr/3aC+ZkD6GEdRVucUnmwGaDqsopwz7cpN9c29+jfTsJKDAKib5lNRnIX6zDztJx9K3Y6TgWqK+jE+9mmvCO+c9PvT9naZWbXqWJk2VD6bzKUOreshMYIvEef1LSBt9lIPsT/efXX83g8Kkd3QH25vHfQhkmEf84/0qnwmyYoBG/yTDK+37sy3qpEiF9jP7K6Nk1yK/X4vzNu6uy88uu6LHAVyFZW5h3cTPBvlfpNXXNJDXnS9YJjyvK2b1zKwfWpCgn+PvJQF968gCbxz9MFmwomj0X/Bg5MIoXLtXAS83wJsl1vy

function getUsersOnlineMessage(numUsersOnline: number) {
  if (numUsersOnline) {
    return `There are ${numUsersOnline} online now!`;
  }
  return "Nobody's here. :(";
}

ItOVzsjrqb4bHT/FDu3JJk/oI6USmBiYkBZS/0fnB9rVhqDSfE2hkhf4UNNp9U8YXZbEFjLfBSlW54bGu5ISaN6Pp42Gwu9J6YQFJA8s5dMvsyqjDK825tXgK2428HlLJDmpYwZnEOwNAXrOVwQoIiaSYnUawpPErSJmdqqQjWMXFl8dZ2CEn7sBXDtDonQuwH4Crg+RzyRvqROLb7z2qqTB3LRjuii9jhq1fSHN0QCjLwQwmjShMyf8wGVEld9G3dKVk/IsP6Y7iJ7noAP10BKJQMjjd3bmDGdFOWFneZ3kA9lNVUUfO1WGAxaBa/l/nKmOUiGtQuoiNU58pTQC5Q==

    uph89wPphQEit8GPlyTdtTPsoe1HQviF7IX1NAtF5HFtvZcYwX5o8JojlyzF2rGeB6NGesFiyz8pbEH+Q/i6PtE0Ugbx1O3vlkXNn2AxJhkKEgMZeC0fq5S794ihq3wON50ruin1hG2Rn/xxjzG1cscKSDtqCotTdxhk5ANrRl/lqNJgnHV0MBpTnpeqFw9wG5LiuLIP8TAQ6Trfsn7eYUkI590QpDlZu/Lws95IhhIjKxkQNTklj0oIxOJe+yZieVxlZg0NPr+dtSexXKiNRUWyGBj4eRh505hHAUIJd0Q=

ViE4xeka483/fjtjTheCoaDyJYRKZfEV1Zd9KVlenJCWUMy+8EimgrxmrjG1KSkrDi9eDhono0v0jqIJv9656jKCtMyZ3M0m4T3fLIILAKaw5R95cQcB2pv4M2wlU5bw+mQxHw3ZQBQZO5+96YtvUWa7DRVWfb3RmyXLXCuz9Zl4ACWt/jO7lPQIIsLwjvBY1Ic/zkR7TroXn4p2LHkUo+77YM0sypUsX8KcsS2O28tfqpn1mxzGqOiuJYfgzKGbe26/cgGVnE8RSePjVm952/Vdhgss2StEBbnsmbutQHxs9UKIfYtozdK8zC0259gPRB3jbda0uimOMoJjtI5uGv09na0Yhty3R1tuBM87uWiZoYLiq0nFPJ+61iM4yhkiahqdKu4+mwvpw3S1Pd8TyekXPGalCcz2ESRyd3dhC/3EjyuG2Wp8xF22LLmIQw+HjTUgtrZr13BXW7xhdsB1+v5EIWGKabbQLNZy/nileX4=

// both of these result in 'true'
Boolean("hello"); // type: boolean, value: true
!!"world"; // type: true,    value: true

Sx5aQQwHkkTkzE06/zpnysKAqd0BkcnrAS3+rB8IHBl+fZyJicZSQgZ/GQCgOqZVTjKhkdSR4NTE+V9Ay2KBN9wyciYdj2hTvt3nOXRspVFbdhVdpj4QfgBxbeljAWLhyN7CsydtSPUKKnChZS2KqjIU/Ypara7yB81oHqrxPLrGQsueOMcI3BAAlYwPevtIzxmKR+Ql8XWJqVFeCzj+guHKiqxntTwkvT8eBUvI72EMRl/7TLtblQ6xbeR42PcGTl0Le1lNHUAPBdnCx1rU8A==

function printAll(strs: string | string[] | null) {
  if (strs && typeof strs === "object") {
    for (const s of strs) {
      console.log(s);
    }
  } else if (typeof strs === "string") {
    console.log(strs);
  }
}

NUrSgfO9wii+NcgfPaFv1GdyGa+bCBdc5x+OzsbHAJ2MqM593BXnxyZ7JaahCwRLHkWf32Ghhx4yUZzYC9hUUiDn4c127dO0H9pR9Bq6+H0yyL4g3lEUUNziHPHQLXUY8SDEEQRZC/mX2Uz7ba8ANvZPMelsGUHHrcQpHKfTXyJhW2Fag/C3VNII8gpRxLVoxKvJUEeOAHolbk1Jl2odbD4gmmpDZLaqD4z+nUat3gg=

TypeError: null is not iterable

p/R4UvQMh2xx7qofDTjHCOTXEFrNo5CUk8EjlicylyJDTnmS3HUh+nlTkDDrU4dTDKCwMcVtKSQYnUPT9v1l4QYZES9Qm2BFH1Abkz6/xQNllCl0NPICz0BO5e/rGXXnDJRAPxu0axOnyCHlbsgcPZOUCzzM//4WZK3j0ERjvSzEzI4YLRb9LD9/RTBCfTiS

function printAll(strs: string | string[] | null) {
  // !!!!!!!!!!!!!!!!
  //  DON'T DO THIS!
  //   KEEP READING
  // !!!!!!!!!!!!!!!!
  if (strs) {
    if (typeof strs === "object") {
      for (const s of strs) {
        console.log(s);
      }
    } else if (typeof strs === "string") {
      console.log(strs);
    }
  }
}

9uF7R8iSyIhz4OrircPJaqZyCuE9XOV2eY0TDWFk2kc2D3B+wsFgdblOoWMldZqLIxkNV1l7eC9r8++D6OvgEVM6Xmu8G9/dGtVovNvJKwlIkr2HM2QICuPlQuQhSSiT1009/r+E9X7xdXkqlGIVjZZbE3+YOtqb3l90gTW+uUxuq7Z0rUjNPlpMKr7xOh7KN36/SJUZjv8iqQJ+7KnzkQ==

RGubdpFwDWX2wMB7zVxSotYFSgIuXwjhjkVxNoatHzgl7VxTf+2sbvm1T+UZw+9qw1LRiMX7uwSUhouZeLFmO6KQC6vha04KP2jq2xVD61prJvbzMnkp8J1EuMGkBFMbPBveZiMQBvCwftcfl4iUIoGtHsKQztq1D334KuR2xUOmENuwJmdyHF07/7otWJvKQm6urZvTpzCqaM9vEfY8EgK+xShEdb7h02ems4Rqpnqs58yVV2f+kP6iU7kGGYzLVw8g0HGcVVbSjDjRiaQSaAB1ZFyXlLcZknZrqi+kPlrM2mpJLnNMtaZEVz0fCqCCXToDOjG5xLC31iXiHbQ62fiXL4Id32k+BMxGPsH3WJqBC90n5aJDC93zsyVgdj+yo/PZbDlKnW+9zdhivDsTKijdo1OwRPfscfNMFZ12WoQNnJgOdVvf4ec6LiZG5NYebw4NMrQh0zkKbRn3qBkiJxTxt9G5WZaQxHh4yV+GCxE=

/39muvkFZZemuRw3JUtvJl20aCtoQlBcfu13DPKITCnVzPCHcjEbp3L3om/5dANkTVUlhQvg4w/NfFRu+fcgB9IEaUd8+wEgGFpR7Ja3GBMP6Na/JA3JaOAv1o80N4sGziEG5xZd7HuSwdAdvqimcg==

function multiplyAll(
  values: number[] | undefined,
  factor: number
): number[] | undefined {
  if (!values) {
    return values;
  } else {
    return values.map((x) => x * factor);
  }
}

相等性缩小

bdtychd9Wtf+nVpJqa/MtvRBDM5BcrV6assA+vwbR0yKT/1AYD6MDlkjBxe6A/7Kb2pTc7vd49e+zPgldghqJsQFUnWz1Gzs3mKu77ymYnKvwuDq4cfgVcwkPwQbxbl2edP/xSdnA9UQHPlh9+D8bTnlKaVTFzLoCUAyKrkSzFNAjUKhA2377j7M+Hh5fOt1ajj0l1MvJcpsNU2VLR5rAcDT7yMi8Dhh0CM9OOTE0Ks=

function example(x: string | number, y: string | boolean) {
  if (x === y) {
    // We can now call any 'string' method on 'x' or 'y'.
    x.toUpperCase();
    y.toLowerCase();
  } else {
    console.log(x);
    console.log(y);
  }
}

QWY5pstWpec9elxPWoAoxiOTYuBXy9nCe5LOf+g0AByXyL0ahviyrJLOxxLM/WyO3lJjq//9RrNNB7axhJ0cSdxOjTlAUwazURgtcYvHaSIWsBSlkbv22A9LltnW2TX7kpi+XHJnkOnkdojH/rC01YjlZ0PPSYbabM/MY73EQ9y+Fq3kOXzaRMuZsUiIGFVqKkz8lPYRntI3rPkedvzDCNw3pjs+R2r9POlaGhKaWYsrFc5YNA1YEvwHqd1Jg9ai2ReWgTkrpXHQNHJTeUDgkLScyG+j5+Cgjp7Fmddb/TBK7ut+eyqSdJVqwJae6El1MAo+rbdaw4EvrncU/nq46NNqL7skstE3rp7ifTld/qKCIWmN/z9VLNesaJjKhJfcR2v3iPI6x3UNh45Z9Br0m6NZCalSsCyiGcyxdzIl99dq1mr5n1QXxIQr28UVGEL+HY/yrmHPUqHUbd+5GioRbA==

r3ezuIhBkJ1JFzWgtGhgdzdB3wxzfhfCDM4StXUz/zFqhy40C20MywL0lsp9+b+HsALIf8AaoyQDTM1g53sP68Dl8LKjI7iEm+Kkw1M6Bszfq/37WBx3CRzujlY0HumaudNAbeTkFZnA/8lxZVPaPE8YbTJjkPq7PMX3qYmLL1zMSF+OlYYfakwg3VwJf/nAXqX8oW8gT9z/B6G/jLbTCI+guQVcnYvNsgNDitjbgHkBHGGh1s/DDJydx7XOtiVpm3tSncx4zjWJexyFzIOiZR/zaGVbsKF/E1rmh4pyrXDwqQcIWhtZdYyBjiWuuvl6bPueNF2u4YZNQ/LwFTUS8VsfII+2NNOolRxWjub7pm7CHB7Epy6Fwsz3qXcI5dadTNzPPeav7rnwYxrdzulGuihvIkMJzSutS96icUqtKShi2JbJLVOQetfVQ9Vh2EbS46IneWSfzywHxdi07hF2+Eggd6XKirzESV/RElcji0Mz5FmvIxaW0CR3bg+XkpPz

function printAll(strs: string | string[] | null) {
  if (strs !== null) {
    if (typeof strs === "object") {
      for (const s of strs) {
        console.log(s);
      }
    } else if (typeof strs === "string") {
      console.log(strs);
    }
  }
}

S8BHa6g+kqqtehkj9B+zPwd+VhGBH9kFbvL9A6V17fbD6fA/hx9Bw4REQ21P7DkaTzJDTb/A4lb9lCA4aJ/LDg2Y0oUtnNndHY9CM5ol32E554yencYb97kXgRF28ISj0uUM5hQVMnAC7u3ITMH+dtgwIuAXuxvHm9IF+24S6EVJCRs4I4IqmHp9/TbMRNWKHfalnQGAy5oSUGkxILAtMrqEhZrxUcH2sSNqkV/BqNpxE75bx+GFQN2YgSVMxx0jP2NELEimE4A+oajdMiDbpY5uk7IVxxIZBONXlawtwhmCc2xy9Y0WQkOYBtMIvf/GArtb1itT+1ZBTNga+/nmo/mdT+NUYSIDdrmz+1VpEvkGzVTxjHTIvLWlpLSKX0lvrsJt+rQ0TK5olAP0txt1Pjh/JzGMWKzShwMqEFfBKLJpLFIoJlOVNZ0Hq+fWv8nMK8gZsbmjSAWRJwNHG8lJl39NjtcVzMpaV9k9SDjNyPrKguDKjMvZm1RnZIM2a4JqERftyrjKav3DBOfBPkQhQtkQ1X8NRZ8UvFfvemg1MQw=

interface Container {
  value: number | null | undefined;
}

function multiplyValue(container: Container, factor: number) {
  // Remove both 'null' and 'undefined' from the type.
  if (container.value != null) {
    console.log(container.value);

    // Now we can safely multiply 'container.value'.
    container.value *= factor;
  }
}

in 运算符缩小

SOJ3wO151MEkdQL5lyKtfRkQAdjzHeplFbz6nc+S2deZYk7JzZ46g0ZMXyK9FitAhP47t17D+H7ILfLjS/Txk/QpHZhht1PeUTJkjNB1iB+RiyKrSunG5GlM0YRR0zEbN45RMTdNCdoEc7xI43hDDeqIjhGLVZdmCd1FcMvK2uJX7hUbV+Qz+NqWcKixPoKC8SWsHK0LflP187DHzgrH2v6ahVCibXaB+DJnQsT2P3ZsIUGfXCR0amUOl2Zp2e6u

PraCuJroBG3l35RSiBVoMXoVa9G0dRdHtLWFcJNnzEfgjMI5+5azeYKWamY9NgyMZWgt/Gn/nT32LfOHTmQJ6ZUs/q8eZNPmMVUjq6ONNUiQ9SWjyzqsrrkhT2oBG53wPsg4Acc10AxH0nOEZ16f2l3ZhJ9n1I8KoJdhymTpWcjBZWAUiJ7yRKM+12E/BZxoJBBnKpvmKy3A7yZRtRfFkiQBY95YTbWX3e1vEm9gzc/z4vHmA+h4pGM9gsD0EhX4zRyMGvXwVe0gjyfhqSjK7IRwnLPe6pTK4v+Ln5DRnfWLxaOJf2+syjAM5K4CbPejfgOhtZBGFITl9IrJITdFPJq452MMNycYYT62azyDSlD98Du6EotN0BLWmnJPK7Jp7aiuy4Q7tm1MkRlYFwJjQ2+ZJSX6AVbJVC2qkogVegE=

type Fish = { swim: () => void };
type Bird = { fly: () => void };

function move(animal: Fish | Bird) {
  if ("swim" in animal) {
    return animal.swim();
  }

  return animal.fly();
}

apvghB7I2UCJjyHSKgatIVS6MgnOrOr04unowi0x43NTji8s28exQJtEHgBNzN3giRz2hFmnlLizy4PPqfVilhZg7aOLggTMIsA0awxyrJ+LMLyhdkt6K73vCrGBrCebZS2dQ2suUFtyDb6qVDIBoq0QK9JswHC8H7cqHaygwn9UnwSEmedcR+Scm9VBfO79LX/LN0GptaJBafn5krNUqcJSHrGdyOCZBkBki9aG+dAvfXIau9bVJWQLdquhp3AI

type Fish = { swim: () => void };
type Bird = { fly: () => void };
type Human = { swim?: () => void; fly?: () => void };

function move(animal: Fish | Bird | Human) {
  if ("swim" in animal) {
    animal;
  } else {
    animal;
  }
}

instanceof 缩小

SOJ3wO151MEkdQL5lyKtffYDQ8ZKt7+tFua62gA5XEU4AwocjHcdEevNO4/VaTkxvt5h1ZqMqLWaZrDL8UTzqlk46AwswgFN0HKXMIG6xkvwuXg8Uv8IVSUYcj73jsouH+0dyUazTZlPbg8RHzqHIWYV1tuplF6Z8RPg12AnrJWaqb/VZCOb9xbKwpKia0gQODfck9Hx3oTBrG5WSvTm5K5kNPMvixcCvwL4L9NpaxcYvLcQtfSxMoMvdwn+dn3dPSVmSJ5319Pr2fV7+aEE6PtvuVHcnZhOIsmJ6NpiTNBT357kgzwI8L5HcI32HsL7hHFR1BUhfEIsq5QvjFNfQ1W6YyQDc38aKuteyaf9lDSPiSoGVV9SAQ8quTjGOT4FSnfvcuiW19kFtkXaMdYUDh8uvxx7R/OzRUskwFNbUggtKy5WLwKandJ96xKkuaoGG8e7r5i+HYyVPVj05CxC4P/TtjIicm2pJLyezu6Q/5da5efj1bvjq6KHp3eAgs44+wHKZL3A60bivixSlcHcD+Fa3EBhw38WNrhhAtaA8gvz9tY500NV3L7JjL4LHyukMxgZAKP1fN7pgGU14eiBFfrqLviTfUPApROOVldmNyYoIjikk8BCbDO12rfPjy5ImkwDYTgGvZYkc0uMImBSsuC123q8C7vYF7KPCawUlJNUxL+m94OfjTtYpU2DiRVKll37Qtt3RljSUlBlvuN2Xk3VCOrtltj2Hvb8Hb3U4CI=

function logValue(x: Date | string) {
  if (x instanceof Date) {
    console.log(x.toUTCString());
  } else {
    console.log(x.toUpperCase());
  }
}

赋值

10nJZQmlsQHiv5vqYNlMTmVF6pCD0+Iw/Rc3d/KfGB7l0CoUFK+FLt0Rw8jvgygqZrhFVpSafq/rs1rePzwf7sN5HxmIoZO6AnFUfUGqBcjUpDQT8ktMehfl7olOVgQHfXiCJWK6YnsyjN3LBaO4mfwjCSw/O5kopiqOd9MbQDLOU4bs4TH3L+hyitcb06c/

let x = Math.random() < 0.5 ? 10 : "hello world!";
x = 1;

console.log(x);
x = "goodbye!";

console.log(x);

d0ax6XVaD0trrNjjuSHUlx34aLgSwmNDYqihqjpydLijtjJAKOQU1J4M0IvbIitH3OBtWdBDaLoPpnOt2bU7zU72B3zmjGoN8cY5397i+8yRzrPlb1pfGv5rmRmyKwTM1U1jG6/iLOOpFqud/Lq/ATrG93qpYqBYuOKRKVMRKq1BphTgvx/UI/Ut2e+FKoPWX2xxFnTLF84yIwtmljcQs3CLdOfSfMA10vegvwoz1g8CLNc+p8RkL/RsitKr+srtVHcuWAvDOVSLoVR71oU7ua931EevFRnnT7X6iVlFEVKfzrX8tTzMXzoX3Zop0af2b2bypVUtKRkGhm+xv0un0/sf4YRX8TFebY/lgph5Et9KFSj1SQgaKdNzpQ7p99hkoXBqcoPU2uX05lTFV5lDcu1z52ZD8NG9dk95Ak3iWgx2p6YzF8n625KlufBbGSsKLVObDegx0ae5nx/s3bHAY4fSzxKmsJVnnAyoGtt4Cw7pRm3eRF1iRhbwvCqUnjND+MjWo9WbdSziEmQzLJThxA==

Ca9MKqb+DRN87ZDAlGXpNm7W3gppJOtEYNWgOk6nKBmqjOwtVFMipDWNhMePJj3y+j+cuPmt88LX63KDEJuz3J2m9uAl9DPNEgfbsxWF1b0LCgrtxuWXKd03yrrCWcaQhsq9yGwF/1emgg+yeJyosmCSLnT9XFkyF9T48iQ+EWjl2irhMPmcOTRqX0VE+mIl

let x = Math.random() < 0.5 ? 10 : "hello world!";
x = 1;

console.log(x);
x = true;

console.log(x);

控制流分析

x89LGMGgLOKwftyxJs+tYFSZx6RmvosUw3IIsRQw7K6mf9GrpMVdLHLma1RCiv/fgrpsUd+qYNxvSgQl7D/cgGyeCapHXP4tTCpacomWt7d9iCKWRG5cBjtx749bqgDCXZKiGE/RkGjMHqcvliljza9W8P9PQLkyeLDE5rYaRhkRZnsIlwl1gAUi92gSsGwZAZUKYoMq8YLzegqCnPDTwruHmTo5mhQ/I12vtKhCc0dbMhhKxMpPduBtK9bVtXO5l5vuFtc31cnnxLmpeSMjfx1sHUzuKOwY9u9StjlAUlq2qv2E4rjnakLKFWquDEqnGe/3osqfsMtTKiX0EJEMH5MmKXbGmccsQ3n3dEB0O06ZH28gq0KExcAuVCMsVi4F

function padLeft(padding: number | string, input: string) {
  if (typeof padding === "number") {
    return " ".repeat(padding) + input;
  }
  return padding + input;
}

0jobq7SUoQ63QFfNdmNCmQdiQxfLXFqQSGTTHrw1UzmaLwQ/F2WI/LH5uc07gtN/QRCZzu8utGAgyE/eR+GUuChRglQ6Cz/QT9FiyK2ItSjZYKwoPfWDPcBEAUrIyfS9La1aXSGGk1/CHvuBhkzyVxDRww1Z5ucuD9w7nu4D0fTQhuzw5YtScLjyVe1SuT3pmFsi77z27VLrGcWcddPT3WM9Kq1RjeXB+ul6Q7Uudwih8vLhT99hgPJU2fab++vI/e0Dc4cMyT6bNhIKqE+D97VqY1b3LN8m/ZslD0byIfpIscwj4jjrurD4/pMvGbwwXHFr6R2ANw2iOUgG1IdiB9NN/OMsO5xnAMq7PqMdZ6csPc9fLf0j7ITkRMXaZ2yMJxnpqczdc5LDM4eki/ae4Y+udNJQhzrwBr9pdkBPTpJjP5InRBx4xKO6r5/5NM7MPNXMC+NYURvSb+Gqkmdjd0T7mdE0hb++f1ZOQWYGv+GEf5lihBfTveGbY7BTN8u2rhRAaDVKxUpc2tPoKvwb0l2Fopo25vCSWGQwVdMFy9qEts4MGwLTiyztWP4x5h0z

b98y2YZTJWcg0XiYn0N/+2iyoIGrQ/X2PR7bpQDgjGEqnEXiR2BulTEPzy6xGY2XvRRvjgYcCn/2tjVQEFDsjRmrOe8Yuf5b0JhZO/+T+SaCDqtQ66LR5ZFiF+ftHxcSOLwmVuPQnH2ZMe7/rC4TN6GNLay7MiyI56sIlyk98YAj/AB5UuJgYf+OhDmk3wHr3JIwp7FDP43rMS8G65tJ47KQ2hgS+DsJEqHcKvmxrpbaZsQwjqEAPGb3i24/6VxXOhCb7yIKiJ09Hs6Ybef0/O1HobOUrQYlSxfnWFRK0KvMAeZDADE1FvPGARpkSuWOr9KdG6m8Scw0IvvR8VnfWGhlh/BA8z+jSHv/lWcpMCs5QyK8Jc2oZL+3uYega3Z4jARcTfI4EJPhRfbIQH5QmA==

function example() {
  let x: string | number | boolean;

  x = Math.random() < 0.5;

  console.log(x);

  if (Math.random() < 0.5) {
    x = "hello";
    console.log(x);
  } else {
    x = 100;
    console.log(x);
  }

  return x;
}

使用类型谓词

x89LGMGgLOKwftyxJs+tYFzMABMYRG6VuoZnrNPXPxawTcvXyE54PR7qH4Fjzf7XJfiqDtPc5X9JjALNPeMJkqGF9kzgRa/15gPzlXcX12O/4B8AsY7RVigtLhH5vtX8BOuOPaH/O80sdCF+LI+NvInl/bFDXhx9iFDrnglU/qifGnCV9kHxqwcw/Qlxr/CsGG+/pVPVygEzV6jWhx9g80IhpsbSMPrsJCwVTAKGObE=

a+5D8atFw0yDYVADtshROvT3B6qvPZGYy0hukG1613iLjhwa29UNSptKGyl6fSwohDs43h1Ya9jokgkv1tgUfFwx0iBxIDQKuA9my7McZIRqP9sH2tIIiIt5Xpygs8fgHjRLKil7eDt76D0t13dJSQ==

type Fish = { swim: () => void };
type Bird = { fly: () => void };
declare function getSmallPet(): Fish | Bird;
function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}

lBHaWCIHrGL9oocQKwScwd175cHjp0WQWu5i7iMmekjeSv6sDm1ckdZ9+x2hz5dj6gIlBtdsvSkjX2rpDlVGJu//OtOeJ7tGdTQfthMb0S5B/ydfYWiQr/NXkDDUM4FliLznJ84kUPD90Hx+CfNDkuQd6fC3fmIre8D67LMOKNVx+BHyh8zzGuC8G62jPXBTf++My6pW9xL3hfgCRah+TgxzZv9QZBNBvoSU99Kv/Soig9SgLKlIdGDZMIwZijnVmjuUGa7ee1U8bN6kjG2opw==

XAzKiGw8wCZJZ/fWh7woIwVjEsEJhrYozHMJbEWmK3sqXc+vTRgyATSwkTYJLN2T1Svd3rJcvYzPyqsoPgQeX+Tg2G2qttBGJ35pfx927ulIaocCG3F1L0SQXeN7vwtxGnuZEA/EBWHmalHLx/4upq0sCENdyzfSLJK5WsKGrr18a7vZKdZu/LH63D3SVn7Z7un+xpUOZM4bqU8RhVSKaA==

type Fish = { swim: () => void };
type Bird = { fly: () => void };
declare function getSmallPet(): Fish | Bird;
function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}
// Both calls to 'swim' and 'fly' are now okay.
let pet = getSmallPet();

if (isFish(pet)) {
  pet.swim();
} else {
  pet.fly();
}

iJ+RqbQktQD1szDSuh4OFdOlQSq8Y/hskAVAyYvhFCMmIBOFV5o7W8lkUcqLKZkRBdt9aRMfBinHZBIpSVnIpP1gx0HJSq1mDsIZTS1CMAKg477TqKpg91OWuJ9vzJ0AdBCT7fjoM4HG93qrjLm1ErzCnYIOiBBAn+gOzRgZVOJBWVveUFv4u9O2oL3gdUAMnLBZMrVP9mgZITc7MbwP3jTNvdAGFEOqBGyuZCkyA45QJ5YT0kxHJIgOgmM63FrQcvfSE29Jri6QksS0dsAnW3kZ5HOIwWuqfTXrZ7i5W6k=

YNYM0tMBS0CiIpnyIVYa5D/4/m5YGKTrvbjcdnwIqYS8zlus23LSXk5j/PXRmUndwspzeUEgftHLDQSEgFAgMCUal5vqPHPZYbnhMl3peRBXlqcIndramMomVjbHrEpxn4Sb9XGfMuM4tzZV9xsoAeQrsxO2zzzsa2N1HvIDCOdcmNbpahWPH8+OTHKJi5vj

type Fish = { swim: () => void; name: string };
type Bird = { fly: () => void; name: string };
declare function getSmallPet(): Fish | Bird;
function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}
const zoo: (Fish | Bird)[] = [getSmallPet(), getSmallPet(), getSmallPet()];
const underWater1: Fish[] = zoo.filter(isFish);
// or, equivalently
const underWater2: Fish[] = zoo.filter(isFish) as Fish[];

// The predicate may need repeating for more complex examples
const underWater3: Fish[] = zoo.filter((pet): pet is Fish => {
  if (pet.name === "sharkey") return false;
  return isFish(pet);
});

yr2t+geACZ504irOhxLR0F+A5i+iAT399+9IZl2eL/CEhlon0OgsTh4aDfUEEv6uSPY0SWDT6I/G4KcHHmRGmCgbU/fimp1b8Y7J21Ax8FPqYNWS5rWsMXq9K35AR3flL81p9eg3nNcSr1tiZbKRIRvS9npLd+D085uPFew+RhM=

可识别的联合

x89LGMGgLOKwftyxJs+tYG1P0eov1taCE/IpO8HoQya85272F0idrWfbbHimi8siFYmW5FZfYVIPUxL+DBup3Arrti4iFWRTtDtyt238eoZkGCS2U0h9AZw6yN+5pS8daxL1oxbFiElgn/J42eZOusb2N1aWmrY0SQkdTLAsQNGMULIFJA9yZfv2ki4RD8FrC8+JWVbpUWq7fV2QF/7FiJvopynnhLq/FFsVyYSWo5URaNG1FMTSO4vkSEyjPlsJsyVny/RDbFMz6vu8VPk9Zx2QHvda63G5tK+SoMKyu04SemXBt9fItU6g1+/8ANQEB2YKkZwxt2pDVb4lPOGQdCEr3TxiZ508QK8HzVJZPrXh5/Tw1JEgQRKc62T7I3IF

DMqA0z9FOGaIht9bkVpkrHYFNUJG+D4vTRKxHj3NHxcMVHYx1TWGKXg0H8YeZvEta0VopoEKLmZXufDsJzomE1vfsBEOHXr9r58l3YuP6p6UkjI+7+Gm/OSHdjWbL/McS4eCXXh6EtNdLj+eM0MI6ja4XqsmX8n7VGrtScn+qL8ZRV7MT8girSfq3gRowQGeWEMVYhekkiOc4AjWey++5hrw89Iy9++l4RPJCSD4iXBEDMBoXUhDkf4o9/wGyFRIo4bkKAZzGKn6ZsdSTXomGIxqNWVcUjpbfs5MvD9Qw68Gsv0KkgHShRMMauT0MUN4yE8K6pnfnr4zuR88mLczy8LOh7R7ISz17Oe3EOXpXDHfKiv2vsQdYkNutKISAKvsL9E9ALNlfIxl92p7rYHjqQ==

interface Shape {
  kind: "circle" | "square";
  radius?: number;
  sideLength?: number;
}

adLsUygHe9qJ4BUEWzOnC9TaRiuTw8MzrpL//OPpRD3RJ7BNtNQfATb6zlv/aZb5OFLFPq9OLB393XKMc/2N3uep4h06BsaTMBYzh6jBwC90kxDgGPzm2+pOvqoZtaZJDdhCkYFXIg8KkPf3cYlwCJQl6uE37gpn1wVjGDC3AP94Mv8F602jK3cu4mGxW1t9tWIrG28Nys0/UI8z7RdpPM+szCRWVWPiQ+4SHHC/vn5PnIoO9OTtIj09i8BG1gVPFVNL3pKrur9V8NKyiHrJ1Y746hPHUbzJCemsyDtli0tyw6RKxzT7Sl+rp1r1+5QDOoxElgqS8jMKucxb3YYYrrsJ71C76Ay2e6W4cAUu7z/h3fGM9TH32jSk/utjfZd/MOVSAHaxM9qpT0Pe1lfHJQ==

interface Shape {
  kind: "circle" | "square";
  radius?: number;
  sideLength?: number;
}

function handleShape(shape: Shape) {
  // oops!
  if (shape.kind === "rect") {
    // ...
  }
}

d9grxHR6qNqW4HiYPdFWpE5ns60Ei3x0mvx66rkwK4+rYz7kGVJwjP4k+mWLpq8Zyi1fOQA8oYUTX4wkWO+58GjoOnZNNu4jGxoTvrJXh3AkqeZIkOXy/7h8vq4x463zNQUDF83zyP0XAU+kS9LVC1HyoabF4+84tp0o1kdBSD6+oEOdRl+N95IrPTdTnlehCerP6kKrwoqL+36P0uOiGQ==

interface Shape {
  kind: "circle" | "square";
  radius?: number;
  sideLength?: number;
}

function getArea(shape: Shape) {
  return Math.PI * shape.radius ** 2;
}

fiOqbQj2gbV9wa0ZCzFlAiqfgMMdoKqvAFcgkKyyH9Aq25ENwqrJNUeuL9z6NeA2bXmfImlIyFaSF1yrWr3RDHZ6jPHNmqDnfpcnj9t2ELFMyk5d83ZZg0SPrd8VLR+rthMYHucdxkXIAGsweA/uyZkTAiJCsr7GygzQJnCyGf1vF3Cv9cu1S9A68Z938EIR+8+Jdawn2dtk0ep9WTEKdeq0eL1BRfzBJ3K9JumSP3r+DoBq9IlOCDWN5rjVDFdA41xycKGZ9aVN+kAN6ePpic5syHDU7PHyRBkk90Z3TurZoRzt54xCMlg1VfUNC/xHQ93HsSgN1pRwv7WSqklcXA==

interface Shape {
  kind: "circle" | "square";
  radius?: number;
  sideLength?: number;
}

function getArea(shape: Shape) {
  if (shape.kind === "circle") {
    return Math.PI * shape.radius ** 2;
  }
}

LLZXOsBTcr6oy5UZM3mzCXwCTPDkVsJOojrhizDLbKzL8NaQD4ydgj2twAHGwQ3wQbJ3BHrmU3eJbQJBUuEbWx/mW+4jevBkPogKYwUnfGAP3/tQKvrYsVlXHnGpTE0FEw3sZsYyijeHdFWX2TbLEMMuiARTwVaUfHxIf9NTU+u02zHnpm/5aRTtJl3RXsr03zDacHdmXxtO02cqiOXYXeqiFk8fcGSymTUErDFZUMDKBb2TAQx++pkpGAHf6UTgCiygTuLDSZxqlqXw7cmWrqAfeNw8x5j32MgOJ+BKZmfDYUAFaNVCJ7NrXNqr/exOFKA3TM5tztDzJJhom2LkmyMgX9kwQr3A/D/iCQ0HuKU=

interface Shape {
  kind: "circle" | "square";
  radius?: number;
  sideLength?: number;
}

function getArea(shape: Shape) {
  if (shape.kind === "circle") {
    return Math.PI * shape.radius! ** 2;
  }
}

PcEbmoc02otLHZUAR+JkyOv9jgsLZi6slb4xqHtIBWRmtYtRZ8FoA9cPQOsG/q5Z66g4i+T58fIMnl874qQF+fyvWGdBzKfMwWWqc9sdfRywAj4RczRQyx8Ozl8mJQATSCDBibbdOHcxHePFBTPfARtso8loXCm43E74L4zLHDwHVgo76Bkiwk8elDQJcASofKdZeOwMJ1AYNhOo1ZlP2LaY0ADPacmY6iYUPWxCiABGs5EsqO+S8FPkDHSscCnaKocLYMq/OHQNm65ryVc3i//H9W9Jal1scZLyiZ6CtjLRiwx0jbrcT9u4RZGAkyNVtrGfds9fwVhYnNq+C5O34Hph+ctBMBYZW8dDyKzxqxfBU36h4LEThfRfuG0GLN99MjckTCH+MrMGU7hpwFAf/4QVMA9+2gowNjflQPMKJdwLKP11F2uul8CheIjaxYtyxXlGW5rEppz/9RQ3+GfqQoe8ZBsdqUQ0WGi5ttL/B7mrVrf8RtvNiahtI6GSwAQD+bdKAIUnEJyi0nZfdBET/5cckvKYCDhvCzeTKeGHg6A0E22GaZ11zBEeFpxzBe8jeDOgk6MLSr51FcV42Yr+R4dY4pwYIhtDqN/SB00kdZd6xlx0FhOfF9W9lxWXVC1eHQTXSDsu/tp8tZvJ2AyzKB6kcI9WRSaMrsFf6JiA3vI=

dakvTp6NXR1Xe2BQlPnHkTq9geQ4bwtf8iss+UCA7A2qKEcw0DtSbYULGyNLfTVfAaR26ZDOKFZx77RM9+Zzm49phin2RlyAP9xkfa9VqMZtS7wnMtsppA7nGC3vqE5gS4KDE/LH/pMmJWuHS2KwSuQR7YESrCLnF8tL/qXpbh+RkQm5p8qzpiHJ0viH2dMO9gmvEmmIKO4dfICg3YOj5s0+WpxAYgreUiuq+7AEx1+vdZkhiSvS66Ny3QxNO+HjmJ8h5VCXEnW6OK7fgdF+A8wos5qtItD2E/Y4leuadDgz45E6uS6OjBWsM+usHHgYQnIGiIrmPsc4ebbBEiO44y3YLk3V6+y7d9rHlq6LjwDwUCGpmUaGgzr8FDntVPGS4AtAgydJ+xIuufhbEeWVMQ==

interface Circle {
  kind: "circle";
  radius: number;
}

interface Square {
  kind: "square";
  sideLength: number;
}

type Shape = Circle | Square;

JpcnJvQ2z0ZP1SEWFdfzg/IQ+EpsDv1qXCQ1kK2SX7V/suBpQih4ImafhYHDKpq09ROelgGp1aX2WBqy5fFIY5Ni+HrEcovL6/VP6gX7JubFS+2CUlSAXTSSsq/o+DQc3B0Ib95mec6isYnGv/ypVN2lYrmi0jBIeVm0xBGsKxZI+IO7A2swaccUOIxN/8ogtvqgFX76mdRkC1UEo+vlcxwlp08Ub6blAt+setad/mCflLfzQDi2JoHfmZzIXWf/vtavDMm5Ch2O8Pf3kJc0HHNPcZl/e2k0CRHxSBwEcVgmxPp1opYiHnJ0gnnfFvRd

M6zd7qT9brh4+On++wOnP0rU/YI/xTHgQriKH22wgaw/BNCbLYH9WYHYiw7fcPuzboHdybq8vGNF+JwwORmnYlPwtlh8wLQuM1A8duiyBFiH1gOgfcxssN0307wjRCHOb0I8mKTDyuqrz4Ywtv1XrQ==

interface Circle {
  kind: "circle";
  radius: number;
}

interface Square {
  kind: "square";
  sideLength: number;
}

type Shape = Circle | Square;

function getArea(shape: Shape) {
  return Math.PI * shape.radius ** 2;
}

fyrVTGx2iM+nO6xL/B4rEGKgzU+E7xLGYZB4e/vKNRy/sadIC2tEUHMtvXJOermUU5kJ344vI8bk0MgMa/Te70KgE7oHHVOKdzsrqG8KaJW4cFcjSHhs4HT7TNEQsrPNiXdxpNHdL97I3nXqkG8a8RRbpSHqU+/xOgA1c4seYcGuF1ZTx79Y+mrGO2qOVf/2MckB/R57mgsQ+QXHOyq+zD4DJpYIzB+Cy5j/Erc4v7jebwEf4dCjURHYjJGynRIKScinRIZiyY7aFWOGwacvQ27zJO2hLk/Lnc3U5Alh53qNl9rcgWeSTBSoZX7UdNceUmN6mKGDGMHVfwbSjaE/+ZCaEdv7RTYeo6g7OYjA3YtTNpDuYkizZ9+xy3yRpmk4cKzKI80vc9Kw6i0m2w8PcqIoOGlIAO8hQRC656JG7z0SDcyNYcTPkxI6sXNL+qUitotFn1Sz7rPp7O8c9TyW2nmu/GKbKHi5EbOuJeRc66wW/XVIio3YfeviUJNjJHZNYSa52OzsnFe0pzo1M4Q32K0U/Kof0xGVdKMJuoFkvbFcQypCZIBysTjOkGH9MimHuyjcDUctZodst4ZC5ickL9zUaemUbNAef2LsWSoJ4QBeJTNJseVLCbM+RAAoFzGJPds9pd1wWLeGXHQFn/pjUDttHDNOw0629qZew751Nvw+cJ0O399KAYeUVJ0kxEfWx25613DUxFyJ5AUOfSAZvIJmWZaHsFltOpAbdYUmsyb5V9AsU3Ea7BOtZXMScOViDopu6eqVIYWNiSepA0GLNYvwgHRpplnIb99zS0kZXS6JfxeE1jS4JNJvb8i6AO3i9zeFTfSAA+q0vdZwHdbIO5TZss22jRXw4P5msUALnkRonyaMyrJsVARH8MLAVcZIpAMR7eLQgXWNRbix6eqcclogLRMSqORCBz8/H0nP168=

OVnmQb2q7nTQYZJtZ0druwQD18sq9apgODR3XP184SrVb1tFJ57GPhyKkgh73piXw1qp9rXOj9MyWGJoCJS2JzUkxZ1XS/YGQkK3GLE1qOY=

interface Circle {
  kind: "circle";
  radius: number;
}

interface Square {
  kind: "square";
  sideLength: number;
}

type Shape = Circle | Square;

function getArea(shape: Shape) {
  if (shape.kind === "circle") {
    return Math.PI * shape.radius ** 2;
  }
}

+nJiNVc9IaRS+GEK/DcGusbK1c0DvPpw3IpMoXeYe4L7COflfE/YmDTflD9B3ZUc5IlcDIDUp6+do3/LjgMMNIU5OQuAsOI8SPX5ENa27krhy8QjWTPeM3AfMtKakxpXXaQT72KsoUaqxrM13iPgaG8R5CRJDODZYQ1rEUleklvwa/f+8b/C59NGTxiRWZNdPjGJ2UBnJyqPeSj8BZ2Vq8ob2V9Ur7xvLsnaa9VvSDD5hb+r56OGoaT3OPMXpZLr

vV4gLrYf/OhOfkixrS0im0vfDrJ4xDfQMkGPLp9hXgj4V+mlgvz/b6NmBnPYaFcy8q/yoeQNcAcSRgbDSjgLMFaUW52pkwWfU2srXDTSQ4exSm4URXK0LML+Sw6uD91SEl9vtuE8HSck2ChNo0axbsV/QX80llWkhPWwPGtAgVV9LW19+crqTwNfPE74VjH9upyuqZBdCbBuR6eGiWssnUIcLNUEbcTGkJYNQrgx7CFUVuth0jZlAYBWolQZVBbknzq4eEnGLjvYcO52tfgiQx+4BIqbXZSNByGQUMRJDT3sKB/NKedS+o/dXpwJCqojZ3DN6Cer8hU1E5egA1jjV3tfab7s0RpvAyJ9zrgVJRbdQc66CXurvG7Lh0uZ2ab5JWrVKXXRydbdFRxtRDUchLbdVFVljOocqz5vz02uqXiDPi6ll3sA4f/UiOmDIlaT3r4hycpf/yDnSN3FuLGCmHQfDoTR5rsw4yaRfA+ZPkc=

6BRYlvQyL8swR4yCwlztzzPYalTVCMPa3SKX2zZWH/KBWWMm9YsDBE1p+tfn9lefKZ5iHQ+CVFq3XdB4/c1jenKBBt5YYLTUuJeGlMGqC35xSp0n4iHMx/pDzwV8k54olPYxzVt+9zsiM8VgVds1a8unDB3pvrmqwdWcv+jM2x2hQGgGcgqZ8HCA4zMRQ3Gy4FLZWlrDyzd2o22fjhw/per4j5kDtPzGwEExH7GUqmrL5t6T9TEcAu9s49Cg6XJ7

interface Circle {
  kind: "circle";
  radius: number;
}

interface Square {
  kind: "square";
  sideLength: number;
}

type Shape = Circle | Square;

function getArea(shape: Shape) {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "square":
      return shape.sideLength ** 2;
  }
}

o+vj88spPWd2tcHmxXse/6yjx+ZlzFDnf8ii/Vp/DmFCBMIP1o8vULSZA4yCA6pG3uJQTGrkbUzRrpG3H9g6vw/u7Q11bVnkrK2CeikaY6cWPcy1WitYaNHsneCYtg5m8Qw1xS+/uHNujOJeCNoP2rvLKxG+HBLfL/Uih/mz9ImVWzrRt5e98DuO9j09L+WLjFj9Q6vecuO6HIX5ALP6H0PxG7ul8v2BEVGMyOatABxoY1NyEM7c8srsdXtG/Itbhvxjbj/eGA3Nol4nXOtPDQzTP6lLcwn+fd1tFWpY3L239w/tdiNet5P2VzLTGITzO1eld+ReFRrWEhkrzCacKTCkyBPtIFuInPsPIkEJl7nhGAxfQedE+5BccXFM47D6o+hMetLckTcgh0nPT70KVwcaKxSJax3CMoPMgkzMvwTKxfHm/kkbFhNbftvsuSfSr6IvwRDLz3vaGVLa/R0PrOml03qFiLY5nvuJx37O/sRVlGLjvaj2lANbQgdxzcxMA3GyV49ub/dE/LBsiYoyvGLgOA1dc/IEwrPuxVMe7TWAwoJZ6zSlrwGOPNma9tgq+GmQotFC/u33ho2iN4ioFh7X8d5UzP0vKACrBdmoTEI3/IkSwPrrYmJt//vYOOUt

YDim318GsU5mni4di2+LS0GZJ7VR4KHT8a5Tq3p4Xlf5sS5bvcp+JgpFEyH+YqUvv2hqn3K4j4A7b7jiRtq5eK5GKNJoVEl/siXlLf98vp090hxCt8qu+Mrh4unEc8v/RK/UgvoMhP2dP3+uIV23jdN65mCBv37oM1DYPto9agJMcwoSJrVPykYcCw1dXOgm+myM0iVoMESeSVg09v39AweTQPFWc8wRRJ18wN8DmU7oL+kAQECrViJzHw2i+qsACI5odcMkXirGrMv7REMCEg==

WgpQ8+KhSczJGK51jKrwb/qxBdCl6SuTWESVOuDQp0u/fDGK5gcYqul3jkr/jWQTKIE0/XYCOmVgfuaBmZGCatvmvB2E+LCNSNOhBzQNzXYWJP9EDxBAdu4HU7auWzkQWdLVmXQepLDDzu3wDX0xZiTSuBTDgqATAqhOysia/fPXREW+bg78LudHma1T4LNZ1eOf5Ddw0KgbEPYzeciTLux5x0gXcalBkxw7Moe/YFjEcSlGqmK51bHUm61DE93u51poBB38PthfgiVcJdyNbqvt+GXwoSYI5VEQDBK6iCz9ym/4CM9o6KLZqYtSSWYfwrqfMYKR94SbxDOkliPKew==

never 型

XbNCjxOOu7UfRFrM6qpHNf3iPz3os5xDcHCeGJPex5SE55YZUMLrcUP272QZjjsT3InKNc5QCEtXiPtMGGTXBA4NkFMIjmNY8+ejFTe6xg3lEcwwP91zRdWGQ1PRjlCWQKEeKinM4f33K9gpRf2O/GVFjBsm65htftbJxs/YSnH0Cx8LkxB9rejcNerEp8m2wn4OkXcr6bipy/hFXA5YwJZyh2MIdc9x3nbn0G0/svxGFwcWZSGUPwmsHIG1EtuA7VYRRj+5BHjmk2Ul6seQZnTbp6ZMGzZZ5lIBAkV/mxI=

穷举检查

k3RZeSBLGAOq3BYyvBoMPVUiR4P5F2KXQwOTKtyDpO00TKAXa6PfsyXX2pLr4+0OXksnMN2uSwFZLZckHKNd+Zn+DWtneFiYItpaFwX7mCD1Q3pKA7s3Tn5Vqzhw0TnBAQyeS/ea0i19DxfOuUT4sEt0thctEwzQk739m0YibxmsfTsAZaHA0UhX/ak9cUE3y/nEiQdHhlAyWoMEsHUv3tl9D4yByEsL3SJanfbPW2ZOOYpemGX8fvVdJYJlXAC7pVw9eoC5x6VB9xcBe1APtZKoKqxCnUpBd1fD/Cb96hyBkptp9GQmcctcKxy8zf74r+qCfH/B+X8T03QI1nYc8YrMdFu3U/zqjJAeHqJvdLk=

yLEQUUq5lMQR9PiRauOdA4KSpBzIECqlkwHLnJ/FTpUMnv4QR8Qym83R1pFR80VtYAOLX1K1Oyl5b2QDMjggZs+VDEFgYEvuu0ZNKYpJk6l/DPBykjCB1LcXkeR9uBAEbn4/u++/weT0caTZZanz49HWwq6DBpW0VJu4+j3+NsWExu+Q9iUR+CgN8Dkc6YwfHfrb72X93h86XUHfZd3A0thoYucA6jw8jFitMU4pMD0=

interface Circle {
  kind: "circle";
  radius: number;
}

interface Square {
  kind: "square";
  sideLength: number;
}
type Shape = Circle | Square;

function getArea(shape: Shape) {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "square":
      return shape.sideLength ** 2;
    default:
      const _exhaustiveCheck: never = shape;
      return _exhaustiveCheck;
  }
}

tnVCHhxnhEyzan6eLZ5/dHAzCY398RA8VZBQ9XemR1EteT2l2YMX93Xy+0pf8DHnlBemG29BVgzbK0bmmIv0y4lyFYHRDEGpS2J6epjoVV0=

interface Circle {
  kind: "circle";
  radius: number;
}

interface Square {
  kind: "square";
  sideLength: number;
}
interface Triangle {
  kind: "triangle";
  sideLength: number;
}

type Shape = Circle | Square | Triangle;

function getArea(shape: Shape) {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "square":
      return shape.sideLength ** 2;
    default:
      const _exhaustiveCheck: never = shape;
      return _exhaustiveCheck;
  }
}