Smarter Type Alias Preservation

  1. type BasicPrimitive = number | string | boolean;
  2. export function doStuff(value: BasicPrimitive) {
  3. if (Math.random() < 0.5) {
  4. return undefined;
  5. }
  6. return value;
  7. }

这个方法中,如果我们获取到内部声明文件,doStuff 返回的类型是

  1. export declare type BasicPrimitive = number | string | boolean;
  2. export declare function doStuff(value: BasicPrimitive): string | number | boolean | undefined;

4.2 之后,我们得到的是

  1. export declare type BasicPrimitive = number | string | boolean;
  2. export declare function doStuff(value: BasicPrimitive): BasicPrimitive | undefined;

这样的结果会让人更好理解。

Leading/Middle Rest Elements in Tuple Types

基本类型 元组
首先复习一下元组的知识点:

  1. // 一对数字类型的元组类型
  2. let a: [number, number] = [1, 2];
  3. // 存储字符串、数字、布尔值的元组类型
  4. let b: [string, number, boolean] = ["hello", 42, true];
  5. // 可以有一个或两个字符串的元组类型
  6. let c: [string, string?] = ["hello"];
  7. c = ["hello", "world"];
  8. // 可以有一个或两个字符串并添加别名的元组类型
  9. let d: [first: string, second?: string] = ["hello"];
  10. d = ["hello", "world"];
  11. // 通过使用rest element,首两位是字符串类型,其余都是布尔类型的元组类型
  12. let e: [string, string, ...boolean[]];
  13. e = ["hello", "world"];
  14. e = ["hello", "world", false];
  15. e = ["hello", "world", true, false, true];

4.2 之前,...rest elements 只能放在元组的最后位置,而现在,rest element 可以放在元组的任何位置(只有一点点限制):

  1. // rest element 放在前面,Leading Rest Elements
  2. let foo: [...string[], number];
  3. foo = [123];
  4. foo = ["hello", 123];
  5. foo = ["hello!", "hello!", "hello!", 123];
// rest element 放在中间,Middle Rest Elements
let bar: [boolean, ...string[], boolean];

bar = [true, false];
bar = [true, "some text", false];
bar = [true, "some", "separated", "text", false];

唯一的限制就是,rest element 后面不能跟着可选元素或者其他rest element。换句话说,一个元组类型只能有一个rest element,并且 rest element 后面不能跟着可选元素。

interface Clown { /*...*/ }
interface Joker { /*...*/ }

let StealersWheel: [...Clown[], "me", ...Joker[]];
//                                    ~~~~~~~~~~ Error!
// A rest element cannot follow another rest element.

let StringsAndMaybeBoolean: [...string[], boolean?];
//                                        ~~~~~~~~ Error!
// An optional element cannot follow a rest element.

这种不在尾部的rest element,可以帮我们拿到任前面何个数相同的参数,加上后面一点其余类型的参数:

declare function doStuff(...args: [...names: string[], shouldCapitalize: boolean]): void;

doStuff(/*shouldCapitalize:*/ false)
doStuff("fee", "fi", "fo", "fum", /*shouldCapitalize:*/ true);

Stricter Checks For The in Operator

in 操作符的右侧使用非对象类型是一个运行时错误。TypeScript 4.2确保可以在设计时捕获它。

"foo" in 42
//       ~~
// error! The right-hand side of an 'in' expression must not be a primitive.

--noPropertyAccessFromIndexSignature

tsconfig 配置
当我们访问对象属性,可以使用中括号语法,或者点操作符:

interface Person {
  name: string;
}
const p: Person = { name: 'Max };
console.log(p.name) // Max
console.log(p['name']) // Max

有一种情况可能导致访问不明确的属性而不报错:

interface Person {
  name: string;
  [key: string]: string;
}
const p: Person = { name: 'Max };
console.log(p.namme) // undefined
console.log(p['namme']) // undefined

因为 “namme” 满足 [key: string]。当开启--noPropertyAccessFromIndexSignature 配置,通过点操作符访问的不明确属性会被警告(但是中括号语法不会被警告)。

interface Person {
  name: string;
  [key: string]: string;
}
const p: Person = { name: 'Max' };
console.log(p.namme)
//          ^^^^^^^^
// Error
console.log(p['namme']) // works fine

该配置项并不在 strict family 中,因为它还不适用于大多数开发者。

abstract Construct Signatures

Understanding Your Project Structure With --explainFiles

Improved Uncalled Function Checks in Logical Expressions

--strictNullChecks 开启情况下,在表达式 &&|| 的情况下,使用未调用的函数,会报错:

function shouldDisplayElement(element: Element) {
    // ...
    return true;
}

function getVisibleItems(elements: Element[]) {
    return elements.filter(e => shouldDisplayElement && e.children.length)
    //                          ~~~~~~~~~~~~~~~~~~~~
    // This condition will always return true since the function is always defined.
    // Did you mean to call it instead.
}

Destructured Variables Can Be Explicitly Marked as Unused

noUnusedLocals 开启的情况下,未使用的变量名会报错:

let [_first, second] = getValues();

现在,在变量名前加下划线,意味着我们不准备使用它。

Declare Missing Helper Function

未命名的的函数名,可以根据调用快速 quick fix,添加方法和类型:

TypeScript 4.2 - 图1


参考: