ts日常类型

1. string、number和boolean

let name: string = '张三'
let age: number = 25
let isMarriage: boolean = true
// 在大多数情况下,这不是必需的。 TypeScript 会尽可能地尝试自动推断代码中的类型。

2. 数组

let books: string[] = ['三国演义', '红楼梦']
let nums: Array<number> = [28, 35]

3. any

let obj: any = { x: 1}
// 当你不想写出一个长类型来让 TypeScript 相信特定的代码行是可以的时,any 类型很有用。

4. 函数

function greet(name: string) {
  console.log("Hello, " + name.toUpperCase() + "!!");
}

function printCoord(pt: { x: number; y: number }) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}
// 可选属性: 对象类型还可以指定它们的部分或全部属性是可选的。 为此,请在属性名称后添加 ?
function printName(obj: { first: string; last?: string }) {
  // ...
}

5. 联合类型

function printId(id: number | string) {
  if (typeof id === "string") {
    // In this branch, id is of type 'string'
    console.log(id.toUpperCase());
  } else {
    // Here, id is of type 'number'
    console.log(id);
  }
}

function welcomePeople(x: string[] | string) {
  if (Array.isArray(x)) {
    // Here: 'x' is 'string[]'
    console.log("Hello, " + x.join(" and "));
  } else {
    // Here: 'x' is 'string'
    console.log("Welcome lone traveler " + x);
  }
}

// 有时你会有一个联合,所有成员都有共同点。 例如,数组和字符串都有一个 slice 方法。 如果联合中的每个成员都有一个共同的属性,则可以使用该属性而不会缩小类型:
function getFirstThree(x: number[] | string) {
  return x.slice(0, 3);
}

6. 类型别名

type Point = {
  x: number;
  y: number;
};
 
// Exactly the same as the earlier example
function printCoord(pt: Point) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}

7. 接口

interface Point {
	x: number;
	y: number
}

function printCoord(pt: Point) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}
// 类型别名和接口的区别
// 1. 扩展接口
// 1.1 Interface
interface Animal {
	name: string
}
interface Bear extends Animal {
	honey: boolean
}
const bear = getBear()
bear.name;
bear.honey;
// 1.2 Type(通过交集扩展类型)
type Animal {
	name: string;
}
type Bear = Animal & {
	honey: boolean;
}
const bear = getBear()
bear.name;
bear.honey;
// 2. 添加新字段
// 2.1 Interface 向现有接口添加新字段
interface Window {
	title: string;
}
interface Window {
	ts: TypeScriptAPI;
}
const src = 'const a = "hello world"';
window.ts.transpileModule(src, {});
// 2.2 type类型创建后无法更改
type Window = {
  title: string;
}

type Window = {
  ts: TypeScriptAPI;
}

 // Error: Duplicate identifier 'Window'.
  1. 类型断言
// 有时你会得到关于 TypeScript 无法知道的值类型的信息。

// 例如,如果你使用的是 document.getElementById,TypeScript 只知道这将返回某种 HTMLElement,但你可能知道你的页面将始终具有具有给定 ID 的 HTMLCanvasElement。

// 在这种情况下,你可以使用类型断言来指定更具体的类型:
const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement;
// 或
const myCanvas = <HTMLCanvasElement>document.getElementById("main_canvas");

// TypeScript 只允许类型断言转换为更具体或更不具体的类型版本。 此规则可防止 “impossible” 强制,例如:
const x = "hello" as number; // Conversion of type 'string' to type 'number' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.

// 有时,此规则可能过于保守,并且不允许可能有效的更复杂的强制转换。 如果发生这种情况,你可以使用两个断言,首先是 any(或 unknown,我们稍后会介绍),然后是所需的类型:
const a = expr as any as T;
  1. 字面类型
// 就其本身而言,字面类型并不是很有价值:
let x: "hello" = "hello";
// OK
x = "hello";
// ...
x = "howdy"; // Type '"howdy"' is not assignable to type '"hello"'.
// 但是通过将字面组合成联合,你可以表达一个更有用的概念 - 例如,只接受一组已知值的函数:
function printText(s: string, alignment: "left" | "right" | "center") {
  // ...
}
// 数字字面类型的工作方式相同:
function compare(a: string, b: string): -1 | 0 | 1 {
  return a === b ? 0 : a > b ? 1 : -1;
}
// 与非字面类型结合使用:
interface Options {
  width: number;
}
function configure(x: Options | "auto") {
  // ...
}
configure({ width: 100 });
configure("auto");
configure("automatic"); // Argument of type '"automatic"' is not assignable to parameter of type 'Options | "auto"'.
  1. 字面推断
declare function handleRequest(url: string, method: "GET" | "POST"): void;
 
const req = { url: "https://example.com", method: "GET" };
handleRequest(req.url, req.method); // Argument of type 'string' is not assignable to parameter of type '"GET" | "POST"'.
// 就是说req.method会被推断为string类型,而不是“GET”,可能在其他地方将其改成“GET”、“POST”之外的字段,从而导致与handleRequest参数类型不符
// 解决办法
// 1. 通过在任意位置添加类型断言来更改推断:
// Change 1:
const req = { url: "https://example.com", method: "GET" as "GET" };
// Change 2
handleRequest(req.url, req.method as "GET");
// 更改 1 表示 “我打算让 req.method 始终具有 _ 字面类型 _"GET"“,防止之后可能将 "GUESS" 分配给该字段。 更改 2 表示 “由于其他原因,我知道 req.method 的值为 "GET"“。
// 2. 可以使用 as const 将整个对象转换为类型字面
const req = { url: "https://example.com", method: "GET" } as const;
handleRequest(req.url, req.method);
// as const 后缀的作用类似于 const,但用于类型系统,确保为所有属性分配字面类型,而不是更通用的版本,如 string 或 number。
  1. null 和 undefined
// JavaScript 有两个原始值用于表示值不存在或未初始化的值: null 和 undefined。
// 非空断言运算符(后缀 !)
// TypeScript 还具有一种特殊的语法,可以在不进行任何显式检查的情况下从类型中删除 null 和 undefined。 在任何表达式之后写 ! 实际上是一个类型断言,该值不是 null 或 undefined:
function liveDangerously(x?: number | null) {
  // No error
  console.log(x!.toFixed());
}
  1. 枚举:它允许描述一个值,该值可能是一组可能的命名常量之一
// 1. 数字枚举
// 我们有一个数字枚举,其中 Up 用 1 初始化。 从那时起,以下所有成员都会自动递增。 换句话说,Direction.Up 的值为 1,Down 的值为 2,Left 的值为 3,Right 的值为 4。
enum Direction {
	Up = 1,
	Down,
	Left,
	Right
}
// 在这里,Up 的值为 0,Down 的值为 1,以此类推
enum Direction {
  Up,
  Down,
  Left,
  Right,
}
// 使用枚举很简单: 只需将任何成员作为枚举本身的属性访问,并使用枚举的名称声明类型:
enum UserResponse {
  No = 0,
  Yes = 1,
}
function respond(recipient: string, message: UserResponse): void {
  // ...
}
respond("Princess Caroline", UserResponse.Yes);
// 没有初始化器的枚举要么需要放在第一位,要么必须在使用数字常量或其他常量枚举成员初始化的数字枚举之后。 换句话说,以下是不允许的:
enum E {
  A = getSomeValue(),
  B,
// Enum member must have initializer.
}

// 2. 字符串枚举
enum Direction {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT",
}
// 3. 异构枚举(从技术上讲,枚举可以与字符串和数字成员混合,但不清楚你为什么要这样做)
enum BooleanLikeHeterogeneousEnum {
  No = 0,
  Yes = "YES",
}
// 4. 计算成员和常量成员
// 前面枚举成员是一个数字常量时,当前枚举成员的值=前一个枚举成员的值+1
enum E1 {
  X,
  Y,
  Z,
}
enum E2 {
  A = 1,
  B,
  C,
}
// 枚举成员使用常量枚举表达式进行初始化。
// 常量枚举表达式是可以在编译时完全评估的 TypeScript 表达式的子集。 一个表达式是一个常量枚举表达式,如果它是:1. 字面枚举表达式(基本上是字符串字面或数字字面)、2. 对先前定义的常量枚举成员的引用(可以源自不同的枚举)、3. 带括号的常量枚举表达式 4. 应用于常量枚举表达式的 +、-、~ 一元运算符之一 5. +、-、*、/、%、<<、>>、>>>、&、|、^ 以常量枚举表达式作为操作数的二元运算符
// 将常量枚举表达式计算为 NaN 或 Infinity 是编译时错误。

// 在所有其他情况下,枚举成员被认为是计算的。
enum FileAccess {
  // constant members
  None,
  Read = 1 << 1,
  Write = 1 << 2,
  ReadWrite = Read | Write,
  // computed member
  G = "123".length,
}


// 5. 联合枚举和枚举成员类型
// 当枚举中的所有成员都具有字面枚举值时,一些特殊的语义就会发挥作用。

// 5.1 首先是枚举成员也变成了类型! 例如,我们可以说某些成员只能具有枚举成员的值
enum ShapeKind {
  Circle,
  Square,
}
 
interface Circle {
  kind: ShapeKind.Circle;
  radius: number;
}
 
interface Square {
  kind: ShapeKind.Square;
  sideLength: number;
}
 
let c: Circle = {
  kind: ShapeKind.Square,
// Type 'ShapeKind.Square' is not assignable to type 'ShapeKind.Circle'.
  radius: 100,
};
// 5.2 另一个变化是枚举类型本身有效地成为每个枚举成员的联合
enum E {
  Foo,
  Bar,
}
 
function f(x: E) {
  if (x !== E.Foo || x !== E.Bar) {
// This comparison appears to be unintentional because the types 'E.Foo' and 'E.Bar' have no overlap.
    // x !== E.Foo 为true时,短路 x !== E.Bar,为false时,x的值肯定是E.Foo,x !== E.Bar也没必要写
  }
}


// 6. 运行时枚举
// 枚举是运行时存在的真实对象, 实际上可以传递给函数
enum E {
  X,
  Y,
  Z,
}
function f(obj: { X: number }) {
  return obj.X;
}
// Works, since 'E' has a property named 'X' which is a number.
f(E);


// 7. 编译时的枚举
// 尽管枚举是运行时存在的真实对象,但 keyof 关键字的工作方式与你对典型对象的预期不同。 相反,使用 keyof typeof 获取将所有 Enum 键表示为字符串的类型。
enum LogLevel {
  ERROR,
  WARN,
  INFO,
  DEBUG,
}
 
/**
 * This is equivalent to:
 * type LogLevelStrings = 'ERROR' | 'WARN' | 'INFO' | 'DEBUG';
 */
type LogLevelStrings = keyof typeof LogLevel;
 
function printImportant(key: LogLevelStrings, message: string) {
  const num = LogLevel[key];
  if (num <= LogLevel.WARN) {
    console.log("Log level key is:", key);
    console.log("Log level value is:", num);
    console.log("Log level message is:", message);
  }
}
printImportant("ERROR", "This is a message");


// 8. 反向映射
// 数字枚举成员还获得从枚举值到枚举名称的反向映射
enum Enum {
  A,
}
let a = Enum.A;
let nameOfA = Enum[a]; // "A"
// TypeScript 将其编译为以下 JavaScript:
"use strict";
var Enum;
(function (Enum) {
    Enum[Enum["A"] = 0] = "A";
})(Enum || (Enum = {}));
let a = Enum.A;
let nameOfA = Enum[a]; // "A"
// 9. const 枚举
// 为了避免在访问枚举值时支付额外生成的代码和额外的间接成本,可以使用 const 枚举
const enum Enum {
  A = 1,
  B = A * 2,
}
// 常量枚举只能使用常量枚举表达式,并且与常规枚举不同,它们在编译期间会被完全删除
//  const 枚举不能有计算成员
const enum Direction {
  Up,
  Down,
  Left,
  Right,
}
 
let directions = [
  Direction.Up,
  Direction.Down,
  Direction.Left,
  Direction.Right,
];
// 在生成的代码中会变成

"use strict";
let directions = [
    0 /* Direction.Up */,
    1 /* Direction.Down */,
    2 /* Direction.Left */,
    3 /* Direction.Right */,
];


// 10. 对象与枚举
// 在现代 TypeScript 中,当具有 as const 的对象就足够时,你可能不需要枚举:
const enum EDirection {
  Up,
  Down,
  Left,
  Right,
}

const ODirection = {
  Up: 0,
  Down: 1,
  Left: 2,
  Right: 3,
} as const;
 
EDirection.Up;
           
(enum member) EDirection.Up = 0
 
ODirection.Up;
           
(property) Up: 0
 
// Using the enum as a parameter
function walk(dir: EDirection) {}
 
// It requires an extra line to pull out the values
type Direction = typeof ODirection[keyof typeof ODirection];
function run(dir: Direction) {}
 
walk(EDirection.Left);
run(ODirection.Right);
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值