目录
五、TypeScript 不适合在 vue 业务开发中使用吗?
六、Property 'name' has no initializer
十五、Property '$router' does not exist on type 'Login'
一、快速上手
TypeScript
是 JavaScript
的强类型版本。然后在编译期去掉类型和特有语法,生成纯粹的 JavaScript
代码。
TypeScript
是 JavaScript
的超集,这意味着他支持所有的 JavaScript
语法。
强类型语言的优势在于静态类型检查。
TypeScript是微软开发的语言。
vue3.0使用ts开发。
是github开源项目:https://github.com/Microsoft/TypeScript
2012 年 10 月诞生。
vscode是用ts编写的:https://github.com/Microsoft/vscode/
装包:
yarn global add typescript
检查版本:
tsc -V
初始化:
tsc --init
index.ts:
-
function greeter(person) {
-
return
"Hello, " + person;
-
}
-
-
let user =
"Jane User";
-
-
document.body.innerHTML = greeter(user);
编程成js文件:
tsc index.ts
index.js:
-
function greeter(person) {
-
return
"Hello, " + person;
-
}
-
var user =
"Jane User";
-
document.body.innerHTML = greeter(user);
类型检查:
如果函数参数声明是字符串,却传了数字,会有警告信息
-
function greeter(person:string) {
-
return
"Hello, " + person;
-
}
-
-
let user =
1;
-
-
document.body.innerHTML = greeter(user);
及时不传参数也会报错:
interface接口:
定义Person包含的字段
-
interface Person {
-
firstName: string;
-
lastName: string;
-
}
-
-
function greeter(person: Person) {
-
return
"Hello, " + person.firstName +
" " + person.lastName;
-
}
-
-
let user = {
firstName:
"Jane",
lastName:
"User" };
-
-
document.body.innerHTML = greeter(user);
使用class创建类:
-
class Student {
-
fullName: string;
-
constructor(public firstName, public middleInitial, public lastName) {
-
this.fullName = firstName +
" " + middleInitial +
" " + lastName;
-
}
-
}
-
-
interface Person {
-
firstName: string;
-
lastName: string;
-
}
-
-
function greeter(person : Person) {
-
return
"Hello, " + person.firstName +
" " + person.lastName;
-
}
-
-
let user =
new Student(
"Jane",
"M.",
"User");
-
-
document.body.innerHTML = greeter(user);
编译后是:
-
var Student =
/** @class */ (
function () {
-
function Student(firstName, middleInitial, lastName) {
-
this.firstName = firstName;
-
this.middleInitial = middleInitial;
-
this.lastName = lastName;
-
this.fullName = firstName +
" " + middleInitial +
" " + lastName;
-
}
-
return Student;
-
}());
-
function greeter(person) {
-
return
"Hello, " + person.firstName +
" " + person.lastName;
-
}
-
var user =
new Student(
"Jane",
"M.",
"User");
-
document.body.innerHTML = greeter(user);
访问网页,index.html:
-
<!DOCTYPE html>
-
<html lang="en">
-
<head>
-
<meta charset="UTF-8">
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
-
<title>Document
</title>
-
</head>
-
<body>
-
<script src="./index.js">
</script>
-
</body>
-
</html>
效果:
自动补全功能:
二、vue的TS
引入Vue文件的时候需要加上.vue
后缀,否则编辑器识别不到
TS路由:
-
import Vue
from
'vue'
-
import VueRouter, { RouteConfig }
from
'vue-router'
-
import Home
from
'../views/Home.vue'
-
-
Vue.use(VueRouter)
-
-
const routes:
Array<RouteConfig> = [
-
{
-
path:
'/',
-
name:
'Home',
-
component: Home
-
},
-
{
-
path:
'/about',
-
name:
'About',
-
// route level code-splitting
-
// this generates a separate chunk (about.[hash].js) for this route
-
// which is lazy-loaded when the route is visited.
-
component:
() =>
import(
/* webpackChunkName: "about" */
'../views/About.vue')
-
}
-
]
-
-
const router =
new VueRouter({
-
mode:
'history',
-
base: process.env.BASE_URL,
-
routes
-
})
-
-
export
default router
-
import Vue
from
'vue'
-
import VueRouter, { RouteConfig }
from
'vue-router'
-
-
Vue.use(VueRouter)
-
-
const routes:
Array<RouteConfig> = [
-
{
-
path:
'/',
-
redirect:
'/login'
-
},
-
{
-
path:
'/login',
-
component:
() =>
import(
'../views/Login.vue')
-
}
-
]
-
-
const router =
new VueRouter({
-
mode:
'history',
-
base: process.env.BASE_URL,
-
routes
-
})
-
-
export
default router
三、使用vue-class-component
https://class-component.vuejs.org/
annotating:注释
加加减减:
-
<template>
-
<div>
-
<div>{{count}}
</div>
-
<button @click="handleSub">减
</button>
-
<button @click="handleAdd">加
</button>
-
</div>
-
<
/template>
-
-
<script>
-
import Vue from 'vue'
-
import Component from 'vue-class-component'
-
-
@Component
-
class Login extends Vue {
-
count = 0
-
-
handleSub() {
-
this.count--
-
}
-
-
handleAdd() {
-
this.count++
-
}
-
}
-
-
export default Login
-
</script>
或者:
-
<template>
-
<div>
-
<div>{{count}}
</div>
-
<button @click="handleSub">减
</button>
-
<button @click="handleAdd">加
</button>
-
</div>
-
<
/template>
-
-
<script>
-
import Vue from 'vue'
-
import Component from 'vue-class-component'
-
-
@Component
-
class Login extends Vue {
-
data() {
-
return {
-
count: 0
-
}
-
}
-
-
handleSub() {
-
this.count--
-
}
-
-
handleAdd() {
-
this.count++
-
}
-
}
-
-
export default Login
-
</script>
v-model:
-
<template>
-
<div>
-
<input v-model="username">
-
</div>
-
</template>
-
-
<script>
-
import Vue
from
'vue'
-
import Component
from
'vue-class-component'
-
-
@Component
-
class Login extends Vue {
-
username =
'admin'
-
}
-
-
export
default Login
-
<
/script>
-
挂载完声明周期:
-
<template>
-
<div>
-
1
-
</div>
-
<
/template>
-
-
<script>
-
import Vue from 'vue'
-
import Component from 'vue-class-component'
-
-
@Component
-
class Login extends Vue {
-
mounted () {
-
console.log('挂载完')
-
}
-
}
-
-
export default Login
-
</script>
计算属性:
-
<template>
-
<div>
-
{{double}}
-
</div>
-
<
/template>
-
-
<script>
-
import Vue from 'vue'
-
import Component from 'vue-class-component'
-
-
@Component
-
class Login extends Vue {
-
count = 1
-
get double() {
-
return this.count * 2
-
}
-
}
-
-
export default Login
-
</script>
父子组件传值:
父组件
-
<template>
-
<div>
-
<Icon :name="visible ? 'xianshimima' : 'buxianshimima'" @onClick="handleVisible">
</Icon>
-
</div>
-
<
/template>
-
-
<script>
-
import Vue from 'vue'
-
import Component from 'vue-class-component'
-
import Icon from '../components/Icon
'
-
-
@Component({
-
components: {
-
Icon
-
}
-
})
-
class Login extends Vue {
-
visible = false
-
-
handleVisible() {
-
this.visible = !this.visible
-
}
-
}
-
-
export default Login
-
</script>
-
子组件
-
<template>
-
<span :class="[`icon iconfont icon-${name}`]" @click="handleClick"></span>
-
<
/template>
-
-
<script lang="ts">
-
import Vue from 'vue'
-
import { Component, Prop } from 'vue-property-decorator'
-
-
@Component
-
class Icon extends Vue {
-
@Prop()
-
name: string
-
-
handleClick() {
-
this.$emit('onClick')
-
}
-
}
-
-
export default Icon
-
</script>
子组件也可以写成这种
-
<template>
-
<span :class="[`icon iconfont icon-${name}`]" @click="handleClick"></span>
-
<
/template>
-
-
<script lang="ts">
-
import Vue from 'vue'
-
import Component from 'vue-class-component'
-
-
const IconProps = Vue.extend({
-
props: {
-
name: String
-
}
-
})
-
-
@Component
-
class Icon extends IconProps {
-
handleClick() {
-
this.$emit('onClick')
-
}
-
}
-
-
export default Icon
-
</script>
增加路由hook:
vue-class-component.ts
-
import Component
from
'vue-class-component'
-
-
Component.registerHooks([
-
"beforeRouteEnter"
-
])
在入口文件main.ts里引入这个文件
在组件里可以使用
-
<script>
-
import Vue
from
'vue'
-
import Component
from
'vue-class-component'
-
-
@Component
-
export
default
class Test2 extends Vue {
-
beforeRouteEnter(to,
from, next) {
-
console.log(
1)
-
next()
-
}
-
}
-
<
/script>
四、vue-property-decorator
https://www.npmjs.com/package/vue-property-decorator
vue属性装饰器
父子组件传值,传参
父组件:
-
<template>
-
<div>
-
<Icon :name="visible ? 'show' : 'hide'" @onClick="handleVisible">
</Icon>
-
</div>
-
<
/template>
-
-
<script lang="ts">
-
import { Vue, Component } from 'vue-property-decorator'
-
import Icon from '../components/Icon.vue
'
-
-
@Component({
-
components: {
-
Icon
-
}
-
})
-
class Login extends Vue {
-
visible = false
-
-
handleVisible(payload:object) {
-
this.visible = !this.visible
-
}
-
}
-
-
export default Login
-
</script>
-
子组件:
-
<template>
-
<span :class="[`icon iconfont icon-${name}`]" @click="handleClick"></span>
-
<
/template>
-
-
<script lang="ts">
-
import { Vue, Component, Prop, Emit } from 'vue-property-decorator'
-
-
@Component
-
class Icon extends Vue {
-
@Prop({ default: 'zhanwei' })
-
name: string
-
-
@Emit('onClick')
-
handleClick() {
-
return { id: 2 }
-
}
-
}
-
-
export default Icon
-
</script>
五、TypeScript 不适合在 vue 业务开发中使用吗?
https://www.zhihu.com/question/310485097/answer/591869966
六、Property 'name' has no initializer
Property 'name' has no initializer and is not definitely assigned in the constructor.
解决办法一:
把tsconfig.json文件里的strict字段改成false
解决办法二:
在属性名后面加叹号,这是一种修饰符,标识忽略
-
<template>
-
<span :class="[`icon iconfont icon-${name}`]" @click="handleClick"></span>
-
<
/template>
-
-
<script lang="ts">
-
import { Vue, Component, Prop, Emit } from 'vue-property-decorator'
-
-
@Component
-
class Icon extends Vue {
-
@Prop({ default: 'zhanwei' })
-
name!: string
-
-
@Emit('onClick')
-
handleClick() {
-
return { id: 2 }
-
}
-
}
-
-
export default Icon
-
</script>
七、下载量对比
八、tsconfig.json
ts的配置
-
{
-
"compilerOptions": {
-
"target":
"esnext",
//编译的目标版本
-
"module":
"esnext",
//指定生成哪个模块系统代码
-
"strict":
true,
//静态类型检查
-
"jsx":
"preserve",
//
-
"importHelpers":
true,
-
"moduleResolution":
"node",
-
"experimentalDecorators":
true,
-
"esModuleInterop":
true,
-
"allowSyntheticDefaultImports":
true,
-
"sourceMap":
true,
// 是否生成map文件
-
"baseUrl":
".",
-
"types": [
-
"webpack-env"
-
],
-
"paths": {
-
"@/*": [
-
"src/*"
-
]
-
},
-
"lib": [
-
"esnext",
-
"dom",
-
"dom.iterable",
-
"scripthost"
-
]
-
},
-
"include": [
-
"src/**/*.ts",
-
"src/**/*.tsx",
-
"src/**/*.vue",
-
"tests/**/*.ts",
-
"tests/**/*.tsx"
-
],
-
"exclude": [
-
"node_modules"
-
]
-
}
九、shims-vue.d.ts
shims: 垫片
由于 TypeScript 默认并不支持 *.vue 后缀的文件,所以在 vue 项目中引入的时候需要创建一个shims-vue.d.ts 文件,放在项目应使用目录下,例如 src/shims-vue.d.ts,用来支持*.vue 后缀的文件;
主要用于 TypeScript 识别.vue 文件,Ts默认并不支持导入 vue 文件,这个文件告诉ts 导入.vue 文件都按VueConstructor<Vue>处理
-
declare
module
'*.vue' {
-
import Vue
from
'vue'
-
export
default Vue
-
}
十、shims-tsx.d.ts
允许你以.tsx结尾的文件,在Vue项目中编写jsx代码
-
import Vue, { VNode }
from
'vue'
-
-
declare global {
-
namespace JSX {
-
// tslint:disable no-empty-interface
-
interface Element extends VNode {}
-
// tslint:disable no-empty-interface
-
interface ElementClass extends Vue {}
-
interface IntrinsicElements {
-
[elem: string]: any;
-
}
-
}
-
}
十一、vuex-class
https://www.npmjs.com/package/vuex-class
使用仓库做加加减减
仓库:
-
import Vue
from
'vue'
-
import Vuex
from
'vuex'
-
-
Vue.use(Vuex)
-
-
interface Payload {
-
key: string,
-
value: any
-
}
-
-
export
default
new Vuex.Store({
-
state: {
-
count:
0
-
},
-
mutations: {
-
setState(state:any,
payload:Payload) {
-
state[payload.key] = payload.value
-
}
-
},
-
actions: {
-
},
-
modules: {
-
}
-
})
页面:
-
<template>
-
<div>
-
<div>{{count}}
</div>
-
<button @click="handleSub">减
</button>
-
<button @click="handleAdd">加
</button>
-
</div>
-
<
/template>
-
-
<script lang="ts">
-
import Vue from 'vue'
-
import Component from 'vue-class-component'
-
import { State, Mutation } from 'vuex-class'
-
-
@Component
-
class Login extends Vue {
-
@State('count') count!:number
-
@Mutation('setState') setState!:Function
-
-
handleSub() {
-
let count = this.count - 1
-
this.setState({ key: 'count', value: count })
-
}
-
-
handleAdd() {
-
let count = this.count + 1
-
this.setState({ key: 'count', value: count })
-
}
-
}
-
-
export default Login
-
</script>
十二、ts
初始化:
在空文件夹里打开终端 -> 输入tsc --init 自动生成tsconfig.json
-
{
-
"compilerOptions": {
-
/* Basic Options */
-
// "incremental": true, /* Enable incremental compilation */
-
"target":
"es5",
/* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
-
"module":
"commonjs",
/* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
-
// "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. */
-
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
-
// "sourceMap": true, /* Generates corresponding '.map' file. */
-
// "outFile": "./", /* Concatenate and emit output to single file. */
-
"outDir":
"./js",
//输出文件夹 /* Redirect output structure to the directory. */
-
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
-
// "composite": true, /* Enable project compilation */
-
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
-
// "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. */
-
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
-
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
-
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
-
// "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. */
-
"esModuleInterop":
true,
/* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
-
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
-
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
-
-
/* 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. */
-
-
/* Advanced Options */
-
"forceConsistentCasingInFileNames":
true
/* Disallow inconsistently-cased references to the same file. */
-
}
-
}
监视ts文件变化,自动编译:
vscode -> 终端 -> 运行任务 -> typescript -> tsc: 监视 - (tsconfig.json的目录)
课堂练习(1):
-
function test(name:string) {
-
console.log(name)
-
}
-
-
test(
'hello3')
-
-
//元组
-
let tuple:[string, number, string] = [
'a',
1,
'b']
-
console.log(tuple)
-
-
//任意值
-
let person:any =
'xu'
-
console.log(person)
-
-
//四要素:调用, 参数,返回值,作用
-
function fun(name:string):string {
-
console.log(name)
-
return name
-
}
-
-
fun(
'xu')
-
-
//never 不可到达
-
const error = ():
never => {
-
throw
new
Error(
'错误')
-
}
-
-
//error()
-
-
-
const loop =
() => {
-
while(
true);
-
}
-
//loop()
-
-
console.log(
1)
-
-
-
//枚举
-
enum Color { Red =
2, Green, Blue }
-
-
console.log(Color.Red)
//2
-
-
enum obj {
-
None,
-
Read,
-
G =
'123'.length
-
}
-
-
console.log(obj)
-
-
enum Enum {
-
A
-
}
-
-
let a = Enum.A
-
console.log(a)
//0
-
-
let na = Enum[a]
-
console.log(na)
//A
-
-
-
-
课堂练习(2):
-
function sayHello(person: string) {
-
return
'Hello,' + person
-
}
-
-
let user:string =
'a'
-
console.log(sayHello(user))
-
-
let num:number =
1
-
-
//没有显示声明类型,则会进行类型推断
-
let a =
'a'
-
a =
'b'
//赋值其他类型,则会报错
-
-
let flag:boolean =
true
-
-
//数字类型的数组
-
let arr:number[] = [
1,
2]
-
let strArr:string[] = [
'a',
'b']
-
let objArr:object[] = [{}]
-
-
//泛型方式
-
let arr1:
Array<number> = [
1]
-
let strArr1:
Array<string> = [
'a',
'b']
-
-
//元组
-
let arr2:[number, string, boolean] = [
1,
'2',
true]
-
-
//null, undefined
-
let my_null:
null =
null
-
let my_undefined:
undefined =
undefined
-
-
//可以是字符串也可以是undefined
-
let c:string |
undefined
-
console.log(c)
-
-
//never 从来不会出现的值
-
// let my_never: never = (() => {
-
// throw new Error()
-
// })()
-
-
//any 任何类型
-
let my_any:any =
'任何类型'
-
console.log(my_any)
-
-
//任何类型的数组
-
let arrAny:any[] = [
'a',
1,
true]
-
-
function run():void {
-
console.log(
'run')
-
}
-
-
run()
-
-
function getName():string {
-
return
'xu'
-
}
-
-
console.log(getName())
-
-
const myRun = ():
void => {
-
console.log(
'myRun')
-
}
-
-
myRun()
-
-
const myGetName = ():
string => {
-
return
'myGetName'
-
}
-
-
console.log(myGetName())
-
-
//构造函数Boolean 创造的不是布尔值
-
//let myBoolean:boolean = new Boolean(1)
-
-
-
-
-
-
-
课堂练习(3):
-
//函数
-
//没有返回值是用void
-
function getInfo(name:string, age:number):string {
-
return
`我叫${name},今年${age}岁。`
-
}
-
-
console.log(getInfo(
'xu',
30))
-
-
let getInfo1 = (name:string,
age:number):
string => {
-
return
`我叫${name},今年${age}岁。`
-
}
-
-
console.log(getInfo(
'xu',
31))
-
-
//完整类型
-
let getInfo2:
(name:string, age:number) => string = (name:string,
age:number):
string => {
-
return
`我叫${name},今年${age}岁。`
-
}
-
-
let getInfo3:
Function = (name:string,
age:number):
string => {
-
return
`我叫${name},今年${age}岁。`
-
}
-
-
//函数可选参数,加个问好
-
function myInfo(name: string, age?: number):string {
-
if (
typeof age ===
'number') {
-
return
`我叫${name},今年${age}岁。`
-
}
else {
-
return
`我叫${name}`
-
}
-
}
-
-
console.log(myInfo(
'xu'))
-
-
//默认值
-
function myInfo1(name: string, age:number = 32):string {
-
if (
typeof age ===
'number') {
-
return
`我叫${name},今年${age}岁。`
-
}
else {
-
return
`我加${name}`
-
}
-
}
-
-
console.log(myInfo1(
'xu'))
-
-
//求和
-
function sum(a:number, b:number):number {
-
return a + b
-
}
-
-
console.log(sum(
1,
2))
-
-
//剩余参数
-
function sum1(...rest:number[]):number {
-
console.log(rest)
//数组
-
return rest.reduce(
(prev, item) => {
-
return prev + item
-
},
0)
-
}
-
-
console.log(sum1(
1,
2,
3,
4,
5))
-
-
//枚举类型
-
// 0: 女, 1:男, 2:保密
-
-
enum Sex {
-
gril,
-
boy,
-
secret
-
}
-
-
let xu:Sex = Sex.boy
-
console.log(xu)
-
let xu1:Sex =
3
-
console.log(xu1)
-
-
function getSex(sex:Sex):string {
-
if (sex === Sex.gril) {
-
return
'我是女孩'
-
}
else
if (sex === Sex.boy) {
-
return
'我是男孩'
-
}
else {
-
return
'保密'
-
}
-
}
-
-
console.log(getSex(xu))
-
-
-
class A {
-
v:number =
100
-
test(num:number) {
-
if (num >
this.v) {
-
console.log(
'大了');
-
}
else
if (num <
this.v) {
-
console.log(
'小了')
-
}
else {
-
console.log(
'对了')
-
}
-
}
-
}
-
-
let a =
new A()
-
-
a.test(
100)
-
-
let isDone:boolean =
false
-
-
let isDone1:object =
new
Boolean(
1)
-
-
let isDone2:
Boolean =
new
Boolean(
1)
-
-
let isDone3:boolean =
Boolean(
1)
-
-
//变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型
-
let something
//let something:any
-
something =
1
-
something =
'a'
-
-
//联合类型
-
let myA: string | number
-
myA =
'a'
-
myA =
1
-
-
-
function getLength(something: string | []):number {
-
return something.length
-
}
-
-
let myB: string | number
-
myB =
'A'
-
myB.length
-
myB =
1
-
//myB.length //报错
-
-
let arr:number[] = [
1,
3,
2]
-
arr.sort(
(a, b) => {
-
return a - b
-
})
-
-
-
console.log(arr)
-
-
function is(ar:string,sr:string):boolean {
-
let result =
true
-
if(ar.length===sr.length){
-
for(
let i=
0;i<ar.length;i++){
-
if(ar.indexOf(sr[i])===
-1){
-
result =
false
-
}
-
}
-
result =
true
-
}
else {
-
result =
false
-
}
-
return result
-
}
-
console.log(is(
"asa",
"aas") )
-
-
-
function isAng(arr:string,trr:string):boolean{
-
if(arr.length===trr.length){
-
for(
var i=
0;i<arr.length;i++){
-
if(arr.indexOf(trr[i])===
-1){
-
return
false
-
}
-
}
-
return
true
-
}
-
return
false
-
}
-
-
console.log(isAng(
'listen',
'silenta'))
-
课堂练习(4):
-
-
//函数重载
-
function add(a:string, b:string):string;
-
function
add(
a:number, b:number):
number;
-
-
function
add(
a:any, b:any):
any {
-
if (
typeof a ===
'string') {
-
return a +
'---' + b
-
}
else {
-
return a + b
-
}
-
}
-
-
console.log(add(
'a',
'b'))
-
-
//类
-
//修饰符 pubulic protected private
-
//静态属性 static
-
class Person {
-
public name: string
-
protected age: number
-
-
static height: number =
170
-
-
constructor(name:string, age:number) {
-
this.name = name
-
this.age = age
-
console.log(Person.height, Person.getHeight())
-
}
-
-
protected getName():string {
-
return
`我的名字叫${this.name}`
-
}
-
-
static getHeight():number {
-
return
this.height
-
}
-
}
-
-
let xu =
new Person(
'xu',
30)
-
//console.log(xu.getName())
-
console.log(Person.getHeight())
-
-
// class Animal {
-
// name:string
-
// constructor(name:string) {
-
// this.name = name
-
// }
-
// sayHi() {
-
// return `My name is ${this.name}`
-
// }
-
// }
-
-
// let a = new Animal('jack')
-
// console.log(a.sayHi())
-
-
//继承
-
class Programmer extends Person {
-
job:string
-
constructor(name:string, age:number, job:string) {
-
super(name, age)
-
this.job = job
-
console.log(
this.age)
-
}
-
getJob() {
-
return
`${this.getName()},年龄${this.age},我的工作是${this.job}`
-
}
-
}
-
-
let xu1 =
new Programmer(
'徐同保',
30,
'web前端')
-
//console.log(xu1.getName())
-
console.log(xu1.getJob())
-
//console.log(xu1.age)
-
-
//抽象类
-
abstract
class Animal {
-
name: string
-
constructor(name: string) {
-
this.name = name
-
}
-
getName():string {
-
return
this.name
-
}
-
abstract eat():
void
-
}
-
-
class Cat extends Animal {
-
food: string
-
constructor(name: string, food: string) {
-
super(name)
-
this.food = food
-
}
-
eat():
void {
-
console.log(
`${this.getName()}爱吃鱼`)
-
}
-
}
-
-
let ketty =
new Cat(
'小猫',
'鱼')
-
ketty.eat()
-
-
//更简练的写法,不用定义name了,也不需要赋值
-
class MyAnimal {
-
constructor(public name:string) {
-
}
-
getName() {
-
return
this.name
-
}
-
}
-
-
let myAnimal =
new MyAnimal(
'小猫')
-
console.log(myAnimal.getName())
-
-
//接口
-
interface Goods {
-
name: string
-
price: number
-
flag: boolean
-
}
-
-
let cartList: Goods[] = [
-
{
-
name:
'苹果',
-
price:
8,
-
flag:
true
-
},
-
{
-
name:
'香蕉',
-
price:
5,
-
flag:
false
-
}
-
]
-
-
function goodsInfo(goods:Goods) {
-
console.log(
`${goods.name}现在${goods.price}元一斤${goods.flag ? ',正在促销' : ''}`)
-
}
-
-
cartList.forEach(
item => {
-
goodsInfo(item)
-
})
-
-
//函数接口
-
interface GoodsInfo {
-
(goods: Goods): string
-
}
-
-
let myGoodsInfo: GoodsInfo = (goods:Goods):
string => {
-
return
`${goods.name}现在${goods.price}元一斤${goods.flag ? ',正在促销' : ''}`
-
}
-
-
//类接口,实现接口的时候使用implements(实现)
-
interface PersonI {
-
name: string,
-
age: number,
-
getName():string
-
}
-
-
interface WebI {
-
name: string,
-
age: number,
-
job: string
-
getName(): string
-
getJob(): string
-
}
-
-
//接口也可以继承
-
interface WebIPlus extends PersonI {
-
job: string,
-
getJob(): string
-
}
-
-
-
class MyPerson implements PersonI {
-
name: string
-
age: number
-
-
constructor(name:string, age:number) {
-
this.name = name
-
this.age = age
-
}
-
-
getName() {
-
return
this.name
-
}
-
}
-
-
class Web extends MyPerson implements WebIPlus {
-
job: string
-
constructor(name: string, age: number, job: string) {
-
super(name, age)
-
this.job = job
-
}
-
-
getJob() {
-
return
this.job
-
}
-
-
getInfo() {
-
return
`${this.name},${this.age},${this.job}`
-
}
-
}
-
-
let xu2 =
new Web(
'xu',
30,
'web')
-
console.log(xu2.getInfo())
-
-
-
-
-
课堂练习(5):
-
let arr:
Array<string> = [
'a',
'b',
'c']
-
-
//泛型函数
-
function getMin<T>(arr:T[]):T {
-
let min:T = arr[
0]
-
arr.forEach(
val => {
-
if (val < min) {
-
min = val
-
}
-
})
-
return min
-
}
-
-
let min = getMin<number>([
5,
2,
8,
4,
4])
-
console.log(min)
-
-
let min1 = getMin<string>([
'd',
's',
'c',
'e',
'f'])
-
console.log(min1)
-
-
//泛型类
-
class Min<T> {
-
list: T[] = []
-
add(params: T):
void {
-
this.list.push(params)
-
}
-
getMin(): T {
-
let min:T =
this.list[
0]
-
this.list.forEach(
val => {
-
if (val < min) {
-
min = val
-
}
-
})
-
return min
-
}
-
}
-
-
//函数接口泛型
-
interface Min<T> {
-
(arr: T[]): T
-
}
-
-
-
//装饰器
-
function logClass(target:any) {
-
console.log(
'我是装饰器', target)
-
target.prototype.name =
'我是装饰器添加的name'
-
target.prototype.getName =
function () {
-
console.log(
'我是装饰器添加的方法')
-
}
-
}
-
-
function logName(params:any) {
-
console.log(params)
-
return
function(target:any, attr:any) {
-
console.log(
'属性装饰器', target)
//实例
-
console.log(
'attr', attr)
//使用装饰器的属性
-
target[attr] = params
-
}
-
}
-
-
// function logName(target:any, attr:any) {
-
// console.log('属性装饰器', target) //实例
-
// console.log('attr', attr) //使用装饰器的属性
-
// target[attr] = 'xu'
-
// }
-
-
@logClass
-
class Person {
-
@logName(
'我是Person类')
-
myName: string |
undefined
-
-
@logName(
40)
-
age:number |
undefined
-
-
getInfo() {
-
console.log(
this.myName,
this.age)
-
}
-
}
-
-
let a =
new Person()
-
console.log(a)
-
a.getInfo()
-
-
-
-
-
-
-
笔记:
TypeScript 中,使用 :
指定变量的类型,:
的前后有没有空格都可以。
TypeScript 只会进行静态检查,如果发现有错误,编译的时候就会报错。
构造函数 Boolean
创造的对象不是布尔值。
当构造函数修饰为 private
时,该类不允许被继承或者实例化。
当构造函数修饰为 protected
时,该类只允许被继承,不允许实例化。
只读属性关键字,只允许出现在属性声明或索引签名或构造函数中。
一个类只能继承自另一个类,但是可以实现多个接口。
变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型。
联合类型使用 |
分隔每个类型。
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
十三、装饰器(Decorator)
装饰器是一个对类进行处理的函数。装饰器函数的第一个参数,就是所要装饰的目标类。
-
@decorator
-
class A {}
-
-
// 等同于
-
-
class A {}
-
A = decorator(A) || A;
如果觉得一个参数不够用,可以在装饰器外面再封装一层函数。
-
function testable(isTestable) {
-
return
function(target) {
-
target.isTestable = isTestable;
-
}
-
}
mixins实例:
-
//装饰器函数,list合并到原型链上
-
const mixins =
(...list:any) => (target:any) => {
-
Object.assign(target.prototype, ...list)
-
}
-
-
//待合并的对象
-
const Foo = {
-
name:
'xu',
-
foo() {
-
console.log(
'foo')
-
},
-
bar() {
-
console.log(
'bar')
-
}
-
}
-
-
//使用装饰器
-
@mixins(Foo)
-
class MyClass {
-
-
}
-
-
//测试
-
let obj =
new MyClass();
-
(obj
as any).foo();
-
(obj
as any).bar();
-
console.log((obj
as any).name)
装饰器有注释的作用。
由于存在函数提升,使得装饰器不能用于函数。
日志实例:
-
//计算器类
-
class Computed {
-
name:string
-
constructor(name:string) {
-
this.name = name
-
}
-
@log
-
add(a:number,
b:number) {
-
console.log(
this.name)
-
return a + b
-
}
-
-
@log
-
sub(a:number,
b:number) {
-
return a - b
-
}
-
}
-
-
//日志装饰器
-
function log(target:any, name:any, descriptor:any) {
-
let oldValue = descriptor.value
-
descriptor.value =
function () {
-
//日志
-
console.log(
`日志:调用${name},参数是${Array.from(arguments)}`)
-
//return oldValue.call(this, ...arguments) //执行老方法
-
return oldValue.apply(
this,
arguments)
-
}
-
return descriptor
-
}
-
-
//测试
-
const computed =
new Computed(
'xu')
-
console.log(computed.add(
2,
4))
-
console.log(computed.sub(
4,
2))
十四、红绿灯
-
class Light {
-
constructor() {
-
this.init()
-
}
-
init() {
-
return
this.light(
3,
'绿灯')
-
.then(
() => {
-
return
this.light(
2,
'红灯')
-
})
-
.then(
() => {
-
return
this.light(
1,
'黄灯')
-
}).then(
() => {
-
this.init()
-
}).catch(
() => {
-
console.log(
'失败了')
-
})
-
}
-
light(time: number,
type: string) {
-
return
new
Promise(
(resolve, reject) => {
-
let timer = setInterval(
() => {
-
console.log(type, time)
-
time--
-
if (time ===
0) {
-
clearInterval(timer)
-
resolve()
-
//reject()
-
}
-
},
1000)
-
})
-
}
-
}
-
-
let ligth =
new Light()
-
interface LampI {
-
loop: number
-
start():
void
-
}
-
-
//红绿灯
-
class Lamp<T> {
-
loop: number
-
constructor(public green: number, public red: number, public yellow: number) {
-
this.loop =
0
-
}
-
start() {
-
let loopFun =
async () => {
-
await
new
Promise(
(resolve) => {
-
setTimeout(
() => {
-
this.loop++
-
this.print()
-
loopFun()
-
},
1000)
-
})
-
}
-
loopFun()
-
}
-
test(a:T) {
-
console.log(a)
-
}
-
private print():
void {
-
if (
this.loop <=
this.green) {
-
console.log(
`绿灯${this.green + 1 - this.loop}`)
-
}
else
if (
this.loop <=
this.green +
this.red) {
-
console.log(
`红灯${this.green + this.red + 1 - this.loop}`)
-
}
else
if (
this.loop <=
this.green +
this.red +
this.yellow) {
-
console.log(
`黄灯${this.green + this.red + this.yellow + 1 - this.loop}`)
-
}
else {
-
this.loop =
1
-
console.log(
`绿灯${this.green}`)
-
}
-
}
-
}
-
-
let lamp =
new Lamp(
3,
2,
1)
-
lamp.start()
-
lamp.test([
1,
2,
3])
-
lamp.test(
'hello')
-
-
-
十五、Property '$router' does not exist on type 'Login'
解决办法:
(1)在使用路由的组件导入路由包:
import VueRouter from 'vue-router';
(2)把this断言为any
(this as any).$router.push('/index')
(3)在类里定义$router属性
-
export
default
class Login extends Vue {
-
$router
-
}
十六、使用createDecorator自定义装饰器
decorators.ts:
-
import { createDecorator }
from
'vue-class-component'
-
-
export
const Log = createDecorator(
(options:any, key:string) => {
-
// 备份原始方法
-
const originalMethod = options.methods[key]
-
-
// 添加日志逻辑
-
options.methods[key] =
function wrapperMethod(...args:any) {
-
// 打印日志
-
console.log(
`日志: ${key}(`, ...args,
')')
-
-
// 执行原始方法
-
originalMethod.apply(
this, args)
-
}
-
})
-
-
-
export
const LogPlus =
(payload: string) => createDecorator(
(options:any, key:string) => {
-
// 备份原始方法
-
const originalMethod = options.methods[key]
-
-
// 添加日志逻辑
-
options.methods[key] =
function wrapperMethod(...args:any) {
-
// 打印日志
-
console.log(
`${payload}日志: ${key}(`, ...args,
')')
-
-
// 执行原始方法
-
originalMethod.apply(
this, args)
-
}
-
})
使用:
-
<template>
-
<div>
-
<div>{{msg}}
</div>
-
<div>{{count}}
</div>
-
<button @click="handleSub(1)">减
</button>
-
<button @click="handleAdd(1)">加
</button>
-
<TestComponent name="hello">
</TestComponent>
-
</div>
-
<
/template>
-
-
<script lang="ts">
-
import { Vue, Component } from 'vue-property-decorator'
-
import { Log, LogPlus } from '../utils/decorators
'
-
import TestComponent from '../components/TestComponent.vue
'
-
-
@Component({
-
components: {
-
TestComponent
-
}
-
})
-
export default class Test extends Vue {
-
msg = 'hello
'
-
count = 0
-
-
@Log
-
handleAdd(step:number) {
-
this.count += step
-
}
-
-
@LogPlus('减法
')
-
handleSub(step:number) {
-
this.count -= step
-
}
-
}
-
</script>
十七、TSLint去掉分号和逗号的检查
-
"trailing-comma": [
false],
-
"semicolon": [
false],
十八、react与TS
脚手架:
npx create-react-app react-ts-app --typescript
按装用到的包:
yarn add react-router-dom redux react-redux redux-thunk redux-logger axios
安装TS版的声明:
yarn add @types/react-router-dom @type/react-redux
十九、图片转base64
-
const getBase64Image =
(url: string) => {
-
return
new
Promise(
(resolve,reject) => {
-
let image =
new Image();
-
// CORS 策略,会存在跨域问题https://stackoverflow.com/questions/20424279/canvas-todataurl-securityerror
-
image.setAttribute(
"crossOrigin",
'Anonymous');
-
image.src = url;
-
image.onload =
() => {
-
let canvas =
document.createElement(
'canvas');
-
canvas.width = image.width;
-
canvas.height = image.height;
-
(canvas
as any).getContext(
'2d').drawImage(image,
0,
0);
-
let result = canvas.toDataURL(
'image/png');
-
resolve(result);
-
}
-
image.onerror =
() => {
-
reject(
'图片流异常');
-
};
-
})
-
-
}
二十、React+TS
受控组件:
-
handleInput(e: ChangeEvent<HTMLInputElement>,
field: string) {
-
// @ts-ignore
-
this.setState({
-
[field]: e.target.value
-
})
-
}
HTMLInputElement:
keyUp事件:
-
handleEnter(e: KeyboardEvent<HTMLInputElement>) {
-
if(e.keyCode ===
13) {
-
this.handleLogin()
-
}
-
}
点击事件:
-
handleVisible(e: MouseEvent<Element>,
count: number) {
-
let { visible } =
this.state
-
this.setState({
-
visible: !visible
-
})
-
}
忽略类型检查:
// @ts-ignore
滚动事件:
-
const handleScroll =
(e: React.UIEvent<HTMLDivElement, globalThis.UIEvent>) => {
-
let scrollTop = (e.target
as Element).scrollTop
-
console.log(scrollTop)
-
}
withRouter:
redux数据读写:
-
import React, { Dispatch }
from
'react'
-
import { connect }
from
'react-redux'
-
import { IState }
from
'../interface'
-
-
interface IProps {
-
list: any[],
-
currentId: number,
-
onSetState:
(key: string, value: any) =>
void
-
onDispatch:
(action: Function) =>
void
-
}
-
-
-
const Sidebar =
(props: IProps) => {
-
const { list, currentId } = props
-
-
const handleNav =
(id: number) => {
-
props.onSetState(
'currentId', id);
-
//@ts-ignore
-
document.getElementById(id +
'').scrollIntoView({
block:
'start',
behavior:
'smooth' })
-
}
-
-
const sidebarDom = list.map(
(item: any) => (
-
<div key={item.id} className={`m-sidebar-item ${currentId === item.id ? 'active' : ''}`} onClick={() => handleNav(item.id) }>{item.title}</div>
-
))
-
-
return (
-
<div className="m-sidebar">
-
{sidebarDom}
-
</div>
-
)
-
}
-
-
const mapStateToProps =
(state: IState) => {
-
return {
-
list: state.book.list,
-
currentId: state.book.currentId
-
}
-
}
-
-
const mapDispatchToProps =
(dispatch: Dispatch<any>) => {
-
return {
-
onSetState(key: string,
value: any) {
-
dispatch({
type:
'SET_STATE', key, value })
-
},
-
onDispatch(action:
Function) {
-
dispatch(action)
-
}
-
}
-
}
-
-
export
default connect(mapStateToProps, mapDispatchToProps)(Sidebar)
reducer:
-
import { IBookState, IAction }
from
'../../interface'
-
-
const defaultState: IBookState = {
-
title:
'小米书城',
-
currentId:
0,
-
isRealScroll:
true,
-
list: [],
-
myBooks: []
-
}
-
-
const reducer =
(state = defaultState, action: IAction) => {
-
switch (action.type) {
-
case
'SET_STATE':
-
let newState =
JSON.parse(
JSON.stringify(state))
-
newState[action.key] = action.value
-
return newState
-
default:
-
return state
-
}
-
}
-
-
export
default reducer
actionCreator.js:
-
import { Dispatch }
from
'react'
-
import Api
from
'../../api'
-
-
const list =
() => (dispatch: Dispatch<any>) => {
-
Api.list().then(
res => {
-
if (res.code ===
200) {
-
dispatch({
type:
'SET_STATE',
key:
'list',
value: res.data })
-
}
-
})
-
}
-
-
export
default {
-
list
-
}
接口:
-
export interface IBookState {
-
title: string,
-
currentId: number,
-
isRealScroll: boolean,
-
list: any[],
-
myBooks: any[]
-
}
-
-
export interface IState {
-
book: IBookState
-
}
-
-
export interface IAction {
-
type: string,
-
key: string,
-
value: any
-
}
登录页hook写法:
-
import React, { useState, MouseEvent, KeyboardEvent }
from
'react'
-
import { RouteComponentProps }
from
'react-router-dom'
-
import Icon
from
'../components/Icon'
-
import Api
from
'../api'
-
-
const Login =
(props: RouteComponentProps) => {
-
const [ username, setUsername ] = useState(
'admin')
-
const [ password, setPassword ] = useState(
'123456')
-
const [ visible, setVisible ] = useState(
false)
-
-
const handleVisible =
(e: MouseEvent, count: number ) => {
-
setVisible(!visible)
-
}
-
-
const handleEnter =
(e: KeyboardEvent<HTMLInputElement>) => {
-
if (e.keyCode ===
13 ) {
-
handleLogin()
-
}
-
}
-
-
const handleLogin =
() => {
-
Api.login({ username, password }).then(
res => {
-
if (res.code ===
200) {
-
localStorage.setItem(
'token', res.data.username)
-
props.history.push(
'/index/home')
-
}
-
})
-
}
-
-
return (
-
<div>
-
<div>
-
<input value={username} onChange={(e) => setUsername(e.target.value)} placeholder="请输入用户名" autoFocus>
</input>
-
</div>
-
<div>
-
<input value={password} onChange={(e) => setPassword(e.target.value)} onKeyUp={ (e) => handleEnter(e) } placeholder="请输入密码" type={ visible ? 'text' : 'password' }>
</input>
-
<Icon name={ visible ? 'show' : 'hide' } onClick={ (e, count) => handleVisible(e, count) } className="m-login-icon">
</Icon>
-
</div>
-
<button onClick={() => handleLogin()}>登录
</button>
-
</div>
-
)
-
}
-
-
export
default Login
登录页class写法:
-
import React, { Component, ChangeEvent, KeyboardEvent, MouseEvent }
from
'react'
-
import { RouteComponentProps }
from
'react-router-dom'
-
import Icon
from
'../components/Icon'
-
import Api
from
'../api'
-
-
interface IState {
-
username: string,
-
password: string,
-
visible: boolean
-
}
-
-
interface IProp extends RouteComponentProps {
-
-
}
-
-
export
default
class LoginClass extends Component<IProp, IState> {
-
constructor(props: IProp) {
-
super(props)
-
this.state = {
-
username:
'admin',
-
password:
'123456',
-
visible:
false
-
}
-
}
-
-
handleInput(e: ChangeEvent<HTMLInputElement>,
field: string) {
-
// @ts-ignore
-
this.setState({
-
[field]: e.target.value
-
})
-
}
-
-
handleVisible(e: MouseEvent<Element>,
count: number) {
-
let { visible } =
this.state
-
this.setState({
-
visible: !visible
-
})
-
}
-
-
handleEnter(e: KeyboardEvent<HTMLInputElement>) {
-
if(e.keyCode ===
13) {
-
this.handleLogin()
-
}
-
}
-
-
handleLogin() {
-
let { username, password } =
this.state
-
Api.login({ username, password }).then(
res => {
-
if (res.code ===
200) {
-
localStorage.setItem(
'token', res.data.username)
-
this.props.history.push(
'/index/home')
-
}
-
})
-
}
-
-
render() {
-
let { username, password, visible } =
this.state
-
return (
-
<div>
-
<div>
-
<input value={username} onChange={(e) => this.handleInput(e, 'username')} placeholder="请输入用户名" autoFocus />
-
</div>
-
<div>
-
<input value={password} onChange={(e) => this.handleInput(e, 'password')} onKeyUp={ (e) => this.handleEnter(e) } placeholder="请输入密码" type={ visible ? 'text' : 'password' }/>
-
<Icon name={ visible ? 'show' : 'hide' } onClick={ (e, count) => this.handleVisible(e, count) } className="m-login-icon"></Icon>
-
</div>
-
<button onClick={() => this.handleLogin()}>登录</button>
-
</div>
-
)
-
}
-
}
Icon组件hook写法:
-
import React, { MouseEvent }
from
'react'
-
-
interface IProps {
-
name: string,
-
className?: string,
-
onClick?:
(e: MouseEvent, count: number) =>
void
-
}
-
-
const Icon =
(props: IProps) => {
-
let { name, className =
'', onClick =
() => {} } = props
-
return (
-
<span className={`icon iconfont icon-${name} ${className}`} onClick={(e) => onClick(e, 1)}></span>
-
)
-
}
-
-
export
default Icon
Icon组件Class写法:
-
import React, { Component, MouseEvent }
from
'react'
-
-
interface IProps {
-
name: string,
-
className?: string,
-
onClick?:
(e: MouseEvent, count: number) =>
void
-
}
-
-
-
export
default
class IconClass extends Component<IProps> {
-
render() {
-
const { name, className =
'', onClick =
() => {} } =
this.props
-
return (
-
<span className={`icon iconfont icon-${name} ${className}`} onClick={(e) => onClick(e, 1)}></span>
-
)
-
}
-
}
ReactElement:
-
import React, { Dispatch, ReactElement }
from
'react'
-
import Header
from
'../components/Header'
-
import Footer
from
'../components/Footer'
-
import { Switch, Route }
from
'react-router-dom'
-
import { connect }
from
'react-redux'
-
import Home
from
'./Home'
-
import MyBooks
from
'./MyBooks'
-
import Me
from
'./Me'
-
-
interface IProps {
-
onSetState:
(key: string, value: any) =>
void
-
onDispatch:
(action: Function) =>
void
-
}
-
-
const Index =
(props: IProps) => {
-
-
const renderComponent =
(Component: ReactElement, title: string) => {
-
setTimeout(
() => {
-
props.onSetState(
'title', title)
-
})
-
-
return Component
-
}
-
-
return (
-
<div className="m-wrap">
-
<Header>
</Header>
-
<Switch>
-
<Route path="/index/home" render={() => renderComponent(
<Home>
</Home>, '小米书城')}>
</Route>
-
<Route path="/index/my_books" render={() => renderComponent(
<MyBooks>
</MyBooks>, '我的书包')}>
</Route>
-
<Route path="/index/me" render={() => renderComponent(
<Me>
</Me>, '个人中心')}>
</Route>
-
</Switch>
-
<Footer>
</Footer>
-
</div>
-
)
-
}
-
-
const mapStateToProps =
() => {
-
return {
-
}
-
}
-
-
const mapDispatchToProps =
(dispatch: Dispatch<any>) => {
-
return {
-
onSetState(key: string,
value: any) {
-
dispatch({
type:
'SET_STATE', key, value })
-
},
-
onDispatch(action:
Function) {
-
dispatch(action)
-
}
-
}
-
}
-
-
export
default connect(mapStateToProps, mapDispatchToProps)(Index)
参考链接:
一起来拥抱强大的TypeScript吧--Ts+Vue完全教程
Learn React with TypeScript 3(英文版):
链接:https://pan.baidu.com/s/1BriHov6-BRiQTIZlcR3dWw
提取码:7erx
转载:https://blog.csdn.net/xutongbao/article/details/105532857