TypeScript泛型参数默认类型 和 新的 --strict 编译选项

更新日期: 2020-01-01阅读: 3.4k标签: 泛型
作者:Marius Schulz
译者:前端小智
来源:https://mariusschulz.com/

TypeScript 2.3 增加了对声明泛型参数默认类型的支持,允许为泛型类型中的类型参数指定默认类型。

接下来看看如何通过泛型参数默认将以下react组件从 JS (和JSX)迁移到 TypeScript (和TSX):

class Greeting extends React.Component {
  render() {
    return <span>Hello, {this.props.name}!</span>;
  }
}


为组件类创建类型定义

咱们先从为 Component 类创建类型定义开始。每个基于类的 React 组件都有两个属性: props 和 state,类型定义结构大致如下:

declare namespace React {
  class Component {
    props: any;
    state: any;
  }
}

注意,这个是大大简化的示例,因为咱们是为了演示泛型类型参数及其默认值的内容。

现在就可以通过继承来调用上面定义的 Component:

class Greeting extends React.Component {
  render() {
    return <span>Hello, {this.props.name}!</span>
  }
}

咱们可以如下方式创建组件的实例:

<Greeting name="world" />

渲染上面组件会生成以下 html

<span>Hello, World!</span>

nice,继续。


使用泛型类型定义 Props 和 State

虽然上面的示例编译和运行得很好,但是咱们的 Component 类型定义不是很精确。因为咱们将 props 和 state 类型设置为 any,所以 TypeScript 编译器也帮不上什么忙。

咱们得更具体一点,通过两种泛型类型: Props 和 State,这样就可以准确地描述 props 和 state 属性的结构。

declare namespace React {
  class Component <Props, State> {
    props: Props;
    state: State;
  }
}

接着创建一个GreetingProps类型,该类型定义一个字符串类型 name 的属性,并将其作为Props类型参数的类型参数传递:

type GreetingProps = { name: string };

class Greeting extends React.Component<GreetingProps, any> {
  render() {
    return <span>Hello, {this.props.name}!</span>;
  }
}

1) GreetingProps 是类型参数Props的类型参数

2) 类似地,any是类型参数 State 的类型参数

有了这些类型,咱们的组件得到更好的类型检查和自动提示:


但是,现在使用 React.Component 类时就必需供两种类型。咱们开着的初始代码示例就不在正确地进行类型检查:

// Error: 泛型类型 Component<Props, State>
// 需要 2 个类型参数。
class Greeting extends React.Component {
  render() {
    return <span>Hello, {this.props.name}!</span>;
  }
}

如果咱们不想指定像GreetingProps这样的类型,可以通过为Props和State类型参数提供any类型来修正代码:

class Greeting extends React.Component<any, any> {
  render() {
    return <span>Hello, {this.props.name}!</span>;
  }
}

这种方法可以让编译器通过,但咱们还有更优雅的做法:泛型参数默认类型


泛型参数默认类型

从 TypeScript 2.3 开始,咱们可以为每个泛型类型参数添加一个默认类型。在下面的例子中,如果没有显式地给出类型参数,那么 Props 和 State 都都是 any 类型:

declare namespace React {
  class Component<Props = any, State = any> {
    props: Props;
    state: State;
  }
}

现在,咱们就可以不用指定泛型类型就可以通过编译器的检查:

class Greeting extends React.Component {
  render() {
    return <span>Hello, {this.props.name}!</span>;
  }
}

当然,咱们仍然可以显式地为Props类型参数提供类型并覆盖默认的any类型,如下所示:

type GreetingProps = { name: string };

class Greeting extends React.Component<GreetingProps, any> {
  render() {
    return <span>Hello, {this.props.name}!</span>;
  }
}

这两个类型参数现在都有一个默认类型,所以它们是可选的,咱们可以仅为Props指定显式的类型参数:

type GreetingProps = { name: string };

class Greeting extends React.Component<GreetingProps> {
  render() {
    return <span>Hello, {this.props.name}!</span>;
  }
}

注意,咱们只提供了一个类型参数。但是,被省略可选类型参数前一个必须要指定类型,否则不能省略。


其它事例

在上一篇中关于 TypeScript 2.2 中混合类的文章中,咱们最初声明了以下两个类型别名:

type Constructor<T> = new (...args: any[]) => T;
type Constructable = Constructor<{}>;

Constructable类型纯粹是语法糖。它可以代替 Constructor<{}> 类型,这样就不必每次都要写泛型类型参数。使用泛型参数默认值,就可以完全去掉附加的可构造类型,并将{}设置为默认类型

type Constructor<T = {}> = new (...args: any[]) => T;

语法稍微复杂一些,但是生成的代码更简洁,Good。


新的 --strict 主要编译选项

TypeScript 2.3 引入了一个新的 --strict 编译器选项,它支持许多与更严格的类型检查相关的其他编译器选项。

TypeScript 加入的新检查项为了避免不兼容现有项目通常都是默认关闭的。虽然避免不兼容是好事,但这个策略的一个弊端则是使配置最高类型安全越来越复杂,这么做每次 TypeScript 版本发布时都需要显示地加入新选项。有了--strict编译选项,就可以选择最高级别的类型安全(了解随着更新版本的编译器增加了增强的类型检查特性可能会报新的错误)。

新的--strict编译器选项包含了一些建议配置的类型检查选项。具体来说,指定--strict相当于是指定了以下所有选项(未来还可能包括更多选项):

  • --strictNullChecks
  • --noImplicitAny
  • --noImplicitThis
  • --alwaysStrict

未来的 TypeScript 版本可能会在这个集合中添加额外的类型检查选项。这意味着咱们不需要监控每个 TypeScript 版本来获得应该在项目中启用的新严格性选项。如果向上述选项集添加了新选项,则在升级项目的 TypeScript 版本后,它们将自动激活。

--strict 编译选项会为以上列出的编译器选项设置默认值。这意味着还可以单独控制这些选项。比如:

--strict --noImplicitThis false 

或者在tsconfig.json 文件指定:

{
  "strict": true,
  "alwaysStrict": false
}
    

这将是开启除--noImplicitThis编译选项以外的所有严格检查选项。使用这个方式可以表述除某些明确列出的项以外的所有严格检查项。换句话说,现在可以在默认最高级别的类型安全下排除部分检查。

改进的 --init 输出

除了默认的--strict设置外,tsc --init还改进了输出。tsc --init默认生成的tsconfig.json文件现在包含了一些带描述的被注释掉的常用编译器选项. 你可以去掉相关选项的注释来获得期望的结果。我们希望新的输出能简化新项目的配置并且随着项目成长保持配置文件的可读性。

通过 tsc --init 编译器可以为构建一个配置文件:

$ tsc --init
message TS6071: Successfully created a tsconfig.json file.

运行此命令后,会当前工作目录中生成一个tsconfig.json文件,生成的配置如下所示:

{
  "compilerOptions": {
    /* Basic Options */
    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd' or 'es2015'. */
    // "lib": [],                             /* Specify library files to be included in the compilation:  */
    // "allowJs": true,                       /* Allow javascript files to be compiled. */
    // "checkJs": true,                       /* Report errors in .js files. */
    // "jsx": "preserve",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
    // "declaration": true,                   /* Generates corresponding '.d.ts' file. */
    // "sourceMap": true,                     /* Generates corresponding '.map' file. */
    // "outFile": "./",                       /* Concatenate and emit output to single file. */
    // "outDir": "./",                        /* Redirect output structure to the directory. */
    // "rootDir": "./",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
    // "removeComments": true,                /* Do not emit comments to output. */
    // "noEmit": true,                        /* Do not emit outputs. */
    // "importHelpers": true,                 /* Import emit helpers from 'tslib'. */
    // "downlevelIteration": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
    // "isolatedModules": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */

    /* Strict Type-Checking Options */
    "strict": true                            /* Enable all strict type-checking options. */
    // "noImplicitAny": true,                 /* Raise error on expressions and declarations with an implied 'any' type. */
    // "strictNullChecks": true,              /* Enable strict null checks. */
    // "noImplicitThis": true,                /* Raise error on 'this' expressions with an implied 'any' type. */
    // "alwaysStrict": true,                  /* Parse in strict mode and emit "use strict" for each source file. */

    /* Additional Checks */
    // "noUnusedLocals": true,                /* Report errors on unused locals. */
    // "noUnusedParameters": true,            /* Report errors on unused parameters. */
    // "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */
    // "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */

    /* Module Resolution Options */
    // "moduleResolution": "node",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    // "baseUrl": "./",                       /* Base directory to resolve non-absolute module names. */
    // "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
    // "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
    // "typeRoots": [],                       /* List of folders to include type definitions from. */
    // "types": [],                           /* Type declaration files to be included in compilation. */
    // "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */

    /* Source Map Options */
    // "sourceRoot": "./",                    /* Specify the location where debugger should locate TypeScript files instead of source locations. */
    // "mapRoot": "./",                       /* Specify the location where debugger should locate map files instead of generated locations. */
    // "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. */
    // "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */

    /* Experimental Options */
    // "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
    // "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
  }
}

注意 --strict 是默认启用的。这意味着在启动一个新的TypeScript项目时,自动进入默认模式。

--checkJS 选项下 .js 文件中的错误

即便使用了--allowJs,TypeScript 编译器默认不会报 .js 文件中的任何错误。TypeScript 2.3 中使用--checkJs选项,.js文件中的类型检查错误也可以被报出.

你可以通过为它们添加// @ts-nocheck注释来跳过对某些文件的检查,反过来你也可以选择通过添加// @ts-check注释只检查一些.js文件而不需要设置--checkJs编译选项。你也可以通过添加// @ts-ignore到特定行的一行前来忽略这一行的错误.

.js文件仍然会被检查确保只有标准的 ECMAScript 特性,类型标注仅在.ts文件中被允许,在.js中会被标记为错误。JSDoc注释可以用来为你的 JS 代码添加某些类型信息,

原文:https://mariusschulz.com/


链接: https://fly63.com/article/detial/7140

TypeScript 泛型的通俗解释

在 TypeScript 中我们会使用泛型来对函数的相关类型进行约束。这里的函数,同时包含 class 的构造函数,因此,一个类的声明部分,也可以使用泛型。那么,究竟什么是泛型?如果通俗的理解泛型呢?

泛型,很多人因它放弃学习 TypeScript?

Java是和typescript一样支持泛型的,当我在大学开始学习Java的时候,我还是一个菜鸟码农,遇到难点(比如泛型)就直接跳过,能学多少学多少,回寝室就LOL开黑。直到大学毕业我依旧没有理解泛型的概念

这些高阶ts内置泛型帮助类型,你用过几个

本文将简要介绍一些工具泛型使用及其实现, 这些泛型接口定义大多数是语法糖(简写), 你可以在 typescript 包中的 lib.es5.d.ts 中找到它的定义, 我们项目的版本

TypeScript的索引类型与映射类型,以及常用工具泛型的实现

相信现在很多小伙伴都在使用 TypeScript(以下简称 TS),在 TS 中除了一些常用的基本类型外,还有一些稍微高级一点的类型,这些就是我本次文章要讲的内容

一文读懂 TypeScript 泛型及应用

泛型是静态类型语言的基本特征,允许将类型作为参数传递给另一个类型、函数、或者其他结构。TypeScript 支持泛型作为将类型安全引入组件的一种方式。

秒懂 TypeScript 泛型工具类型!

如果你刚接触 TypeScript 不久,在阅读 TypeScript 内置工具类型的用法和内部实现的文章时,可能会看到 Pick 工具类型,对于该类型的语法你可能会感到陌生。

如何在 TypeScript 中使用泛型

泛型是静态类型语言的一个基本特征,允许开发人员将类型作为参数传递给另一个类型、函数或其他结构。当开发人员使他们的组件成为通用组件时,他们赋予该组件接受和强制执行在使用该组件时传入的类型的能力

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!