Coder Social home page Coder Social logo

libin1991 / ts-react-todo Goto Github PK

View Code? Open in Web Editor NEW

This project forked from sl1673495/ts-react-app

0.0 0.0 0.0 223 KB

TypeScript + React Hook 实现todo demo

Home Page: https://juejin.im/post/5dddde68e51d4541c24658c1

HTML 8.45% CSS 3.97% TypeScript 87.59%

ts-react-todo's Introduction

为什么要用TypeScript

  1. TypeScript 解决了什么痛点? - justjavac的回答 - 知乎 https://www.zhihu.com/question/308844713/answer/574423626

  2. 渐进式,就算前期用了很多any,关键接口的类型定义已经能带来很多便利。

  3. 公司统一技术栈。

编写第一个 TypeScript 程序

类型注解

function greeter(person: string) {
  return "Hello, " + person;
}

let user = "Yee";

console.log(greeter(user));

接口

让我们继续扩展这个示例应用。这里我们使用接口来描述一个拥有 firstNamelastName 字段的对象。 在 TypeScript 里,只在两个类型内部的结构兼容,那么这两个类型就是兼容的。 这就允许我们在实现接口时候只要保证包含了接口要求的结构就可以,而不必明确地使用 implements 语句。

interface Person {
  firstName: string;
  lastName: string;
}

function greeter(person: Person) {
  return "Hello, " + person.firstName + " " + person.lastName;
}

let user = {
  firstName: "Yee",
  lastName: "Huang",
};

console.log(greeter(user));

最后,让我们使用类来改写这个例子。 TypeScript 支持 JavaScript 的新特性,比如支持基于类的面向对象编程。

让我们创建一个 User 类,它带有一个构造函数和一些公共字段。因为类的字段包含了接口所需要的字段,所以他们能很好的兼容。

还要注意的是,我在类的声明上会注明所有的成员变量,这样比较一目了然。

class User {
  fullName: string;
  firstName: string;
  lastName: string;

  constructor(firstName: string, lastName: string) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.fullName = firstName + " " + lastName;
  }
}

interface Person {
  firstName: string;
  lastName: string;
}

function greeter(person: Person) {
  return "Hello, " + person.firstName + " " + person.lastName;
}

let user = new User("Yee", "Huang");

console.log(greeter(user));

基础类型

布尔值

let isDone: boolean = false;

数字

let decLiteral: number = 20;

字符串

let name: string = "bob";
name = "smith";

数组

let list: number[] = [1, 2, 3];

第二种方式是使用数组泛型,Array<元素类型>

let list: Array<number> = [1, 2, 3];

元组 Tuple

元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。 比如,你可以定义一对值分别为 stringnumber 类型的元组。

let x: [string, number];
x = ["hello", 10]; // OK
x = [10, "hello"]; // Error

枚举

enum 类型是对 JavaScript 标准数据类型的一个补充。 像 C# 等其它语言一样,使用枚举类型可以为一组数值赋予友好的名字。

enum Color {
  Red,
  Green,
  Blue,
}
let c: Color = Color.Green;

any

有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。 这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么我们可以使用 any 类型来标记这些变量:

let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // 也可以是个 boolean

在对现有代码进行改写的时候,any 类型是十分有用的,它允许你在编译时可选择地包含或移除类型检查。并且当你只知道一部分数据的类型时,any 类型也是有用的。 比如,你有一个数组,它包含了不同的类型的数据:

let list: any[] = [1, true, "free"];

list[1] = 100;

void

某种程度上来说,void 类型像是与 any 类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void

function warnUser(): void {
  console.log("This is my warning message");
}

声明一个 void 类型的变量没有什么大用,因为你只能为它赋予 undefinednull

let unusable: void = undefined;

null 和 undefined

TypeScript 里,undefinednull 两者各自有自己的类型分别叫做 undefinednull。 和 void 相似,它们的本身的类型用处不是很大:

let u: undefined = undefined;
let n: null = null;

never

never 类型表示的是那些永不存在的值的类型。 例如, never 类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; 变量也可能是 never 类型,当它们被永不为真的类型保护所约束时。

never 类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是 never 的子类型或可以赋值给never 类型(除了 never 本身之外)。 即使 any 也不可以赋值给 never

下面是一些返回 never 类型的函数:

// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
  throw new Error(message);
}

object

object 表示非原始类型,也就是除 numberstringbooleansymbolnullundefined 之外的类型。

使用 object 类型,就可以更好的表示像 Object.create 这样的 API。例如:

declare function create(o: object | null): void;

create({ prop: 0 }); // OK
create(null); // OK

create(42); // Error
create("string"); // Error
create(false); // Error
create(undefined); // Error

类型断言

有时候你会遇到这样的情况,你会比 TypeScript 更了解某个值的详细信息。

let someValue: any = "this is a string";

let strLength: number = (someValue as string).length;

高级类型

联合类型

export type Union = string | number

export let u:Union

u = '2'

u = 3

交叉类型

type Foo = {
  foo: any
}

type Bar = {
  bar : any
}
type Intersection =  Foo & Bar

let i: Intersection = {
  foo: 'foo',
  bar: 'bar',
}

索引类型

索引类型的查询操作符 keyof T 表示类型 T 的所有公共属性的字面量联合类型

interface Obj {
  a: number
  b: string
}
let key: keyof Obj // let key: "a" | "b"

类型守卫

举个简单的例子,根据某个值是Foo类型或Bar类型,分别做不同的处理。

type Foo = {
  foo: any
}

type Bar = {
  bar : any
}

type Unknown = Foo | Bar

function judge(val: Unknown): void {
  if (val.hasOwnProperty('foo')) {
    (val as Foo).foo = 'ok'
  }else if (val.hasOwnProperty('bar')) {
    (val as Bar).bar = 'ok'
  }
}

这里要用到类型断言,因为TypeSciprt不会根据hasOwnProperty的结果作为类型判断的依据,但是它提供了另一种方式类型守卫

// 类型守卫方案
function isFoo(val: any): val is Foo {
  return val.hasOwnProperty('foo')
}

function judge2(val: Unknown): void {
  if (isFoo(val)) {
    val.foo = 'ok'
  }else {
    // 自动被推断为Bar
    val.bar = 'ok'
  }
}

接口

可选属性

接口里的属性不全都是必需的。 有些是只在某些条件下存在,或者根本不存在。例如给函数传入的参数对象中只有部分属性赋值了。

interface Square {
  color: string;
  area: number;
}

interface SquareConfig {
  color?: string;
  width?: number;
}

function createSquare(config: SquareConfig): Square {
  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 来指定只读属性:

interface Point {
  readonly x: number;
  readonly y: number;
}

任意属性

用任意的字符串索引,使其可以得到任意的结果。

interface Person {
  name: string
  age: number
  [x: string]: any
}

let man: Person = {
  name: 'James',
  age: 30,
  height: '180cm'
}

函数

函数类型接口

interface Add {
  (x: number, y: number): number
}

let add: Add = (a, b) => a + b

函数类型别名

除此之外,还有一种更简洁的方式就是使用类型别名

类型别名使用 type 关键字

type Add = (x: number, y: number) => number

let add: Add = (a, b) => a + b

函数重载

function overload (a: number, b: number): number
function overload (a: string, b: string): string
function overload (a: any, b: any): any {
  return a + b
}

泛型

灵活的类型传参

function make(args) {
  return args;
}

make([]);

这样子是没有任何提示的,ts 没法推断出返回值和传入的参数是同一个类型。

function make<T>(args: T) {
  return args;
}

const num = make<number>(2);

此时再输入num. 就会出现提示。

也可以简化成

const num = make(2);

此时 T 会自动被推断为 number 类型。

在泛型约束中使用类型参数

你可以声明一个类型参数,且它被另一个类型参数所约束。 比如,现在我们想要用属性名从对象里获取这个属性。 并且我们想要确保这个属性存在于对象 obj 上,因此我们需要在这两个类型之间使用约束。

function getProperty<T, K extends keyof T> (obj: T, key: K ) {
  return obj[key]
}

let x = {a: 1, b: 2, c: 3, d: 4}

getProperty(x, 'a') // okay
getProperty(x, 'm') // error

泛型的类型推断

现在有个需求,函数 withA 接受一个对象,并且向这个对象上混入 a 属性并返回。

function withA(arg: object): object & { a: number } {
  return Object.assign(arg, { a: 2 });
}

const result = withA({ b: 2 });

此时不会提示 result 上应有的 b 字段,因为 ts 并不知道返回的对象拥有传入对象身上的属性。

利用泛型来约束入参和出参是相同的结构,再利用联合类型增加额外属性。

function withA<T>(arg: T): T & { a: number } {
  return Object.assign(arg, { a: 2 });
}

const result = withA({ b: 2 });

例如 React 的 useState

function useState<S>(initialState: S): [S, SetState<S>] {
  let state = initialState;
  const setState = (newState: S) => {
    state = newState;
    return state;
  };

  return [state, setState];
}

type SetState<S> = (newState: S) => void;

教程分享

入门

TypeScript Handbook入门教程 https://zhongsp.gitbooks.io/typescript-handbook/content/

进阶

巧用 TypeScript系列 一共五篇
https://juejin.im/post/5c8a518ee51d455e4d719e2e

TS 一些工具泛型的使用及其实现
https://zhuanlan.zhihu.com/p/40311981

实验

TypeScript Playground 有任何想法都可以在上面编写尝试 https://www.typescriptlang.org/play/

ts-react-todo's People

Contributors

sl1673495 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.