微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

疑问:TS

总结 TS

疑问

  • declare
  • module
  • .d.ts 的运行方式
  • interface ComponentOptions { } 中的 < >
  • !
  • ts 会自动引入项目中没有 export 的 ts 文件,作为类型。而且会引起奇怪的错误。例如:创建 src/czb.ts 后,main.ts 中 new Vue 的 router 类型报错。
  • 可以多个关键字一起使用吗?比如 private(私有) 和 readonly
  • 注释:ts 会检查所有模块的类型,包括对图片的引入都需要定义类型

module

  • TypeScript 有一个特性来补充现有的类型,叫做模块补充 (module augmentation)。
import Vue from 'vue'

declare module 'vue/types/vue' {
  // 给 vue 实例补充属性声明,例如:vue-router 的 $router、$route 等属性
  interface Vue {
    $myProperty: string
  }
}

——————————————————————————————————————————————————————————————————————————————————

TS(未完成)

TypeScript for the New Programmer

What is JavaScript? A Brief History

TypeScript: A Static Type Checker 静态类型检查

A Typed Superset of JavaScript

Syntax 语法

  • TypeScript doesn’t consider any JavaScript code to be an error because of its syntax. This means you can take any working JavaScript code and put it in a TypeScript file without worrying about exactly how it’s written. TS 内可以放入任何可运行的 JS

Types

  • However, TypeScript is a typed superset, meaning that it adds rules about how different kinds of values can be used. The earlier error about obj.heigth was not an error about the syntax of the program, but instead an error about using a kind of value (a type) in an incorrect way. TS 只规定了如何使用不同类型的值
  • Later, we’ll learn about settings you can use to configure how strictly TypeScript checks your code. TS 对代码进行检查的严格程度可以配置

Runtime Behavior 运行时行为

  • TypeScript is also a programming language that preserves the runtime behavior of JavaScript. For example, dividing by zero in JavaScript produces Infinity instead of throwing a runtime exception. TypeScript never changes the runtime behavior of JavaScript code. TS 不会改变代码的运行时行为,例如 JS 中除于 0 会等于无穷大而不是报错,TS 中也一样。

Erased Types 删除的类型

  • TypeScript’s type system is erased, meaning that once your code is compiled, there is no persisted type information in the resulting JavaScript code. TS 编译后的代码不包含类型

Learning JavaScript and TypeScript

  • Because TypeScript shares syntax and runtime behavior with JavaScript, TS 和 JS 的语法和运行时行为是一样的
  • For example, there about 20 times more StackOverflow questions tagged javascript than typescript JS 相对于 TS 而言更更容易出现堆栈溢出

TypeScript for JavaScript Programmers

Types by Inference 推断类型

  • TypeScript knows the JavaScript language and will generate types for you in many cases. For example in creating a variable and assigning it to a particular value, TypeScript will use the value as its type. TS 在很多情况下会自动判断类型。例如,在创建变量时给予赋值
let helloWorld = "Hello World";

Defining Types 自定义类型

  • Some design patterns can be hard to automatically provide types for automatically (because they might use dynamic programming) in those cases TypeScript supports an extension of the JavaScript language which offers places for you to tell TypeScript what the types should be. 运行时赋值无法推断出类型,需要用户自定义
  • You can then declare that a JavaScript object conforms to that shape of your new interface by using syntax like : TypeName after a variable declaration: 类型声明之后,使用 TypeName 语法声明变量 user 符合这个 interface 类型
  • 注释: interface 只限定了最小包含,给 user 赋值的对象可以包含处 interface 声明外的其他属性
interface User {
  name: string;
  id: number;
}

const user: User = {
  name: "Hayes",
  id: 0
};
  • Because JavaScript supports classes and object-orient programming, so does TypeScript - an interface declaration can also be used with classes: interface 类型可以用于 class 创建的对象
  • Interfaces can be used to annotate parameters and return values to functions: Interfaces 可以用于注释函数的返回和参数
function getAdminUser(): User {
  //...
}

function deleteUser(user: User) {
  // ...
}
  • There are already a small set of primitive types available in JavaScript: boolean, bigint, null, number, string, symbol, object and undefined, which you can use in an interface. 继承自 JS 的类型有 boolean, bigint, null, number, string, symbol, object and undefined,可以在 Interfaces 类型中使用
  • TypeScript extends this list with a few more. for example: TS 扩展的包括如下
    • any (allow anything) 任意类型
    • unknown (ensure someone using this type declares what the type is) 使用该类型时才进行声明
    • never (it’s not possible that this type could happen) 这个类型代表不可能发生,例如抛出错误的函数
    • void (a function which returns undefined or has no return value). 返回未定义或者没有返回值,例如没有 return 的函数
  • You’ll see quite quickly that there are two syntaxes for building types: Interfaces and Types - you should prefer interface, and use type when you need specific features. 构建类型有两种方法 Interfaces(接口) and Types,Interfaces 比较常用,Types 是为了实现某些特定功能
  • 疑问:Interfaces 是一种类型,那么 Types 是什么?

Composing Types 组合类型

  • The two most popular techniques you would use in everyday code to create new types by working with many smaller types are Unions and Generics. 通过 Unions 和 Generics 组合小类型为复杂类型

Unions 联合

  • A union is a way to declare that a type could be one of many types. Unions 是指多种类型之一
  • For example, you could describe a boolean type as being either true or false: 也可以直接声明具体值,会自动判断类型
function getLength(obj: string | string[]) {
  return obj;
}

type WindowStates = "open" | "closed" | "minimized";
  • TypeScript understands how code changes what the variable could be with time, you can use these checks to narrow the type down. 如果有多种类型,TS 可以根据 === 来判断在不同代码路径下的具体类型
    • string typeof s === "string"
    • number typeof n === "number"
    • boolean typeof b === "boolean"
    • undefined typeof undefined === "undefined"
    • function typeof f === "function"
    • array Array.isArray(a)
function wrapInArray(obj: string | string[]) {
  if (typeof obj === "string") {
    return [obj];
//          ^ = (parameter) obj: string
  } else {
    return obj; // 这个 obj 会被判断为数组
  }
}

Generics 泛型

  • You can get very deep into the TypeScript generic system, but at a 1 minute high-level explanation, generics are a way to provide variables to types. Generics 是为类型提供变量的方法,例如:声明数组类型中每一项的类型
  • 注释:例子2中,<>内是一个 Interfaces 类型
type StringArray = Array<string>;

type ObjectWithNameArray = Array<{ name: string }>;
  • You can declare your own types which use generics: 泛型可以在为变量进行声明时才确定
interface Backpack<Type> {
  add: (obj: Type) => void;
  get: () => Type;
}

// This line is a shortcut to tell TypeScript there is a
// constant called `backpack`, and to not worry about where it came from 声明一个常量 backpack 的类型是 Backpack 并指明这仅仅是一个声明,不需要理会该常量在何处定义
declare const backpack: Backpack<string>;

// object is a string, because we declared it above as the variable part of Backpack。 上面 Backpack 声明中,表明 Type 是可变部分
const object = backpack.get();

// Due to backpack variable being a string, you cannot pass a number to the add function 不能传递 number 类型
backpack.add(23);

Structural Type System 结构形式体系

  • In a structural type system if two objects have the same shape, they are considered the same. 在结构类型系统中如果两个对象具有相同的结构就被视为相同
  • 注释:实际为具有包含的结构就被视为相同
  • 注释:并不是所有变量都要声明类型的,未声明类型的变量名赋值时不会进行类型检查
interface Point {
  x: number;
  y: number;
}

function printPoint(p: Point) {
  console.log(`${p.x}, ${p.y}`);
}

// prints "12, 26"
const point = { x: 12, y: 26, z: 33 };
printPoint(point);
  • If the object or class has all the required properties, then TypeScript will say they match regardless of the implementation details. 如果对象或类具有所有必需的属性,那么无论实现细节如何,TypeScript都会说它们匹配。
class VirtualPoint {
  x: number;
  y: number;

  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
  }
}

const newVPoint = new VirtualPoint(13, 56);
printPoint(newVPoint); // prints "13, 56"

Next Steps

TypeScript for Java/C# Programmers

TypeScript for Functional Programmers 函数式编程中的 TS

TypeScript Tooling in 5 minutes TS库

Installing TypeScript

npm install -g typescript

Building your first TypeScript file

Compiling your code 编译代码

tsc greeter.ts

Type annotations 类型注释

  • Type annotations in TypeScript are lightweight ways to record the intended contract of the function or variable. 类型注释是 TS 注释的一种轻量级方法
function greeter(person: string) {
  return "Hello, " + person;
}
  • Notice that although there were errors, the greeter.js file is still created. You can use TypeScript even if there are errors in your code. But in this case, TypeScript is warning that your code will likely not run as expected. 即使 TS 检查有错误,js 文件依然会被创建,TS 仅仅只是进行提示

Interfaces 接口

Classes

  • Also of note, the use of public on arguments to the constructor is a shorthand that allows us to automatically create properties with that name. 在类的构造函数中使用 public 是一个速写方式,它使这个类及创建的实例包含了这个属性
class Student {
  fullName: string;
  constructor(
    public firstName: string,
    public middleInitial: string,
    public lastName: string
  ) {
    this.fullName = firstName + " " + middleInitial + " " + lastName;
  }
}

Running your TypeScript web app

  • Notice, too, that you can right-click on a symbol and use refactoring to rename it.
  • 疑问:更有利于重构?编辑器的重构功能是否靠谱?

What is the Handbook ?

About this Handbook

How is this Handbook Structured

  • The handbook is split into two sections: 这手册分为两部分
    • The Handbook 手册
    • The Handbook Reference 手册参考,参考手册是对某些特定部分的详细介绍没有连续性

Non-Goals

Get Started

Basic Types

Introduction 介绍

  • In TypeScript, we support much the same types as you would expect in JavaScript, with a convenient enumeration type thrown in to help things along. TS 中基本类型和 JS 基本相同,多提供了一个枚举类

Boolean

let isDone: boolean = false;

Number

let decimal: number = 6;
let hex: number = 0xf00d; // 16进制数值
let binary: number = 0b1010; // 2进制
let octal: number = 0o744; // 8进制

String

let color: string = "blue";

let sentence: string = `Hello, my name is ${fullName}.

Array

  • Array types can be written in one of two ways. In the first, you use the type of the elements followed by [] to denote an array of that element type: 数组类型有两种方式定义
  • 注释:这里的类型 Array 首字母大写
let list: number[] = [1, 2, 3];

// 注释:泛类型,官方教程中这个例子好像是错误
let list: Array<number> = [1, 2, 3];

Tuple 元组

  • Tuple types allow you to express an array with a fixed number of elements whose types are known, but need not be the same. 元组用来表示有固定数量项的数组,并且可以给每项定义类型
// Declare a tuple type
let x: [string, number];
// Initialize it
x = ["hello", 10]; // OK

Enum 枚举

  • an enum is a way of giving more friendly names to sets of numeric values.枚举是为一组数值提供友好名称的方式
enum Color {
  Red,
  Green,
  Blue
}
let c: Color = Color.Green; // c === 1
  • By default, enums begin numbering their members starting at 0. You can change this by manually setting the value of one of its members. 枚举默认从0开始编码,可以手动设置一个值来改变
enum Color {
  Red,
  Green = 2,
  Blue
}
let a: Color = Color.Red; // a === 0
let b: Color = Color.Green; // b === 2
let c: Color = Color.Blue;  // c === 3
  • A handy feature of enums is that you can also go from a numeric value to the name of that value in the enum. 可以通过枚举值来反向获得枚举名称
enum Color {
  Red = 1,
  Green,
  Blue
}
let colorName: string = Color[2];

console.log(colorName); // Displays 'Green' as its value is 2 above

Any

  • These values may come from dynamic content, e.g. from the user or a 3rd party library. 来至用户或第三方库的未知类型可以使用 Any
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
  • However, variables of type Object only allow you to assign any value to them.You can’t call arbitrary methods on them, even ones that actually exist: Object 类型只允许为它赋值,不能调用任何方法即使实际存在
let notSure: any = 4;
notSure.ifItExists(); // okay, ifItExists might exist at runtime
notSure.toFixed(); // okay, toFixed exists (but the compiler doesn't check)

let prettySure: Object = 4;
prettySure.toFixed(); // Error: Property 'toFixed' doesn't exist on type 'Object'.

Void

  • You may commonly see this as the return type of functions that do not return a value: 一般用于不返回任何值的函数
  • 注释:JS 中没有返回的函数实际返回 undefined
function warnUser(): void {
  console.log("This is my warning message");
}
  • Declaring variables of type void is not useful because you can only assign null (only if --strictNullChecks is not specified, see next section) or undefined to them: 把一个变量声明为 void 类型没有实际意义,只能给它赋值 null 和 undefined,且当未指定 --strictNullChecks 时 null 才被允许
let unusable: void = undefined;
unusable = null; // OK if `--strictNullChecks` is not given

Null and Undefined

  • In TypeScript, both undefined and null actually have their own types named undefined and null respectively. Much like void, they’re not extremely useful on their own: TS 中 null 和 undefined 都有自己的类型,但是没有太大的意义
// Not much else we can assign to these variables! 
// 疑问:不能再给这些变量赋值了?
let u: undefined = undefined;
let n: null = null;
  • By default null and undefined are subtypes of all other types. That means you can assign null and undefined to something like number. 默认情况下 undefined 和 null 是所有类型的子集,即可以把它们赋值给任意类型
  • 注释:never 才是所有类型的子类,即 never 可以赋值给 undefined 类型的变量,但是反过来不行。
  • However, when using the --strictNullChecks flag, null and undefined are only assignable to any and their respective types (the one exception being that undefined is also assignable to void). 当设置了 --strictNullChecks 后,null 和 undefined 只能赋值给其自身类型,有个例外 undefined 可以赋值给 void 类型。
  • 注释:@vue/cli 创建的 ts 项目默认设置了 --strictNullCheck
  • This helps avoid many common errors. In cases where you want to pass in either a string or null or undefined, you can use the union type string | null | undefined. 设置 --strictNullCheck 有助于避免错误,如果需要传入多种类型可以使用 union 类型

Never

  • The never type represents the type of values that never occur. For instance, never is the return type for a function expression or an arrow function expression that always throws an exception or one that never returns; never 代表从未出现的值,例如抛出错误的函数,从不会出现返回结果
  • Variables also acquire the type never when narrowed by any type guards that can never be true. ?
  • The never type is a subtype of, and assignable to, every type; however, no type is a subtype of, or assignable to, never (except never itself). Even any isn’t assignable to never. never 类型是所有类型的子类,但是没有类型是 never 的子类,即 never 只能分配给自身,即使是 any 类型都不能接收 never 类型的值
function error(message: string): never {
  throw new Error(message);
}

// Inferred return type is never 自动推断返回类型为 never
function fail() {
  return error("Something failed");
}

Object

  • object is a type that represents the non-primitive type, i.e. anything that is not number, string, boolean, symbol, null, or undefined. object 类型表示当前类型非 number, string, boolean, symbol, null, or undefined
  • With object type, APIs like Object.create can be better represented. For example: obejct 类型用于检查原生 window.Object 对象的 api 是否被正确使用。例如:Object.create 要求参数是一个 object 对象
  • 注释:Object.create 要求传入的 object 类型的对象,也可以是一个 interface 类型的变量。当不知道对象的具体属性时使用 object 类型。
function create(o: Object): void {
  console.log(Object.keys(o).keys);
}
create({ a: 1, b: 2 });

Type assertions 类型断言

  • Sometimes you’ll end up in a situation where you’ll know more about a value than TypeScript does. 用来告诉 ts 类型检查,这个变量是什么类型
  • Type assertions have two forms. One is the “angle-bracket” syntax: 类型断言有两种方式,一种使用<>实现。、
  • 注释:在 @vue/cli 创建的项目中,这种方式不被推荐
let someValue: any = "this is a string";

let strLength: number = (<string>someValue).length;
  • And the other is the as-syntax: 另一种使用 as 语法
let someValue: any = "this is a string";

let strLength: number = (someValue as string).length;
  • however, when using TypeScript with JSX, only as-style assertions are allowed. 在 JSX 中使用 TS 时,只能使用 as 语法

A note about let

Interfaces

Introduction 介绍

Our First Interface

function printLabel(labeledObj: { label: string }) {
  console.log(labeledObj.label);
}

let myObj = { size: 10, label: "Size 10 Object" };
printLabel(myObj);
  • It’s worth pointing out that the type checker does not require that these properties come in any sort of order, only that the properties the interface requires are present and have the required type. Interfaces 类型只要求具有这些属性,不要求完全相同及顺序

Optional Properties 可选属性

  • Not all properties of an interface may be required. 并非所有属性都是必须的
interface SquareConfig {
  color?: string;
  width?: number;
}

function createSquare(config: SquareConfig): { color: string; area: number } {
  let newSquare = { color: "white", area: 100 };
  if (config.color) {
    newSquare.color = config.color;
  }
  if (config.width) {
    newSquare.area = config.width * config.width;
  }
  return newSquare;
}

let mySquare = createSquare({ color: "black" });

Readonly properties 只读属性

  • Some properties should only be modifiable when an object is first created. You can specify this by putting readonly before the name of the property: 某些属性只在首次创建时才能修改
interface Point {
  readonly x: number;
  readonly y: number;
}

let p1: Point = { x: 10, y: 20 };
p1.x = 5; // error!
  • TypeScript comes with a ReadonlyArray type that is the same as Array with all mutating methods removed, so you can make sure you don’t change your arrays after creation: TS 提供了 ReadonlyArray 来定义只读数组类型
  • 注释:只读数组不可以赋值给其他变量,但只读接口的属性可以被赋值给其他变量
  • 注释:只读数组中引用类的项的属性是可以被修改的,只读只限制浅层
let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!
  • You can still override it with a type assertion, though: 可以通过断言覆盖只读
a = ro as number[];

readonly vs const

  • Variables use const whereas properties use readonly. 只读变量使用 const,对象的只读属性才使用 readonly

Excess Property Checks

  • Object literals get special treatment and undergo excess property checking when assigning them to other variables, or passing them as arguments. If an object literal has any properties that the “target type” doesn’t have, you’ll get an error: 将字面量对象赋值给注释了接口类型的变量或参数时会进行额外的检查,不允许该字面量对象含有接口不存在属性
interface Point {
  x: number;
  y: number;
}
function printPoint(p: Point) {
  console.log(`${p.x}, ${p.y}`);
}

const point = { x: 12, y: 26, z: 33 }; // 这样是可行的,不是字面量对象
printPoint(point);

printPoint({ x: 12, y: 26, z: 33 }); // 这样会报错

const point: Point = { x: 12, y: 26, z: 33 }; // 这样也会报错
  • The easiest method is to just use a type assertion: 使用类型断言,可以绕过上面对于字面量的判断
interface SquareConfig {
  color?: string;
  width?: number;
}
function createSquare(config: SquareConfig): { color: string; area: number } {
  // ...
}

let mySquare = createSquare({ width: 100, opacity: 0.5 } as SquareConfig);
  • 注释:断言只能作用于可接受范围,不能强制转化明确的错误
interface SquareConfig {
  color: string; // 这里为非可选接口属性时,下面的断言将报错
  width: number;
}
function createSquare(config: SquareConfig): { color: string; area: number } {
  // ...
}

let mySquare = createSquare({ width: 100, opacity: 0.5 } as SquareConfig); // 这个断言会出错
  • However, a better approach might be to add a string index signature if you’re sure that the object can have some extra properties that are used in some special way. 可以通过字符串索引来给接口添加自定义属性,推荐方法
  • 注释:这种方式 propName 指向的属性名不能够在 vscode 中出现智能提醒
  • 注释:接口最好能定义所有可能用到的属性,这样更有利于只能提醒
interface SquareConfig {
  color?: string;
  width?: number;
  [propName: string]: any;
}
  • 注释:当赋值的字面量对象包含属性,但是不包含接口中任何一个属性,会出现报错
interface Abc {
  color?: string;
}
function dosome(abc: Abc): string {
  return "";
}

const abc: Abc = { czb: 1 }; // 会报错

const abc = { czb: 1 };
dosome(abc); // 会报错

const abc: Abc = {} // 不会报错

const abc = {};
dosome(abc); // 不会报错
  • For more complex object literals that have methods and hold state, you might need to keep these techniques in mind, but a majority of excess property errors are actually bugs. That means if you’re running into excess property checking problems for something like option bags, you might need to revise some of your type declarations. 大多数多余属性是个 bug,通过修改类型定义来接收多余属性是比较好的方式,而不是选择绕过它们。

Function Types

  • In addition to describing an object with properties, interfaces are also capable of describing function types. 接口可以用来描述函数
  • This is like a function declaration with only the parameter list and return type given. Each parameter in the parameter list requires both name and type. 参数列表中的所有值都要有名称和类型
interface SearchFunc {
  (source: string, subString: string): boolean;
}

let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) { // 疑问:不需要重复定义,也可以写为 mySearch = function(source, subString) {
  let result = source.search(subString);
  return result > -1;
};
  • For function types to correctly type check, the names of the parameters do not need to match. 参数的名称并不一定要互相匹配,它会根据参数的顺序应用接口中定义的类型
interface SearchFunc {
  (source: string, subString: string): boolean;
}

const mySearch: SearchFunc = function(src, sub) {
  const result = src.search(sub);
  return result > -1;
};

Indexable Types 可索引类型

interface StringArray {
  [index: number]: string;
}

let myArray: StringArray;
myArray = ["Bob", "Fred"];

let myStr: string = myArray[0];

——————————————————————————————————————————————————————————————————————————————————

TS装饰器(未完成)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐