lbwa / set.sh-stale

✍A place which is used to share my programming experiences in Chinese. 一个分享代码经历的地方。
https://set.sh
0 stars 0 forks source link

typescript collections #18

Open lbwa opened 6 years ago

lbwa commented 6 years ago

使用技巧

// key 为变量,类型为 string,对应的属性值为 number 类型
// 即 option 的所有属性键值均为 number 类型,除非形如 age 键名,另外特别指定类型
interface option {
  [key: string]: number
  age: number
}
// 示例中泛型表示输出与输入的值类型必须一致
function createFn<T>(arg: T): T {
  return arg
}

// 使用
// 方法 1 :显式地指出泛型的运行时类型。
// 调用时确定了类型 string ,即传入的参数必须为 string
let output = createFn<string>('hello')
// 方法 2 : 利用类型推论使用泛型
// 编译器将根据参数类型来设置泛型的运行时类型。
let output = createFn('hello')

:在泛型的类型未确定时,不能调用有关参数的属性(即泛型约束)。

function loggingIdentity<T>(arg: T): T {
  // 泛型在被调用时,可能是任何类型,而此时没有任何地方表明这个可能是任何类型的变量 arg
  // 具有 length 这个属性,故将报错
  console.log(arg.length)
  return arg
}
function loggingIdentity<T>(arg: T[]): T[] {
  // 泛型的类型不影响 arg 是数组,故可正常运行
  console.log(arg.length)
  return arg
}
lbwa commented 6 years ago

报错

报错: 无法重新声明块级作用域变量 xxx

TS2451: Cannot redeclare block-scoped variable 'xxx'

在排除当前模块中不存在同名属性之后仍报错。

原因:在 ts 中,若当前文件中未出现 importexport 关键词时,ts 编译器将认为当前文件中所有的内容都在 全局作用域 中,即使实际情况是他们都存在于当前模块作用域中。这种情况常出现在 nodejs 的环境下,因为在 nodejs 中使用 commonjs 来引入和导出模块。

In TypeScript, just as in ECMAScript 2015, any file containing a top-level import or export is considered a module. Conversely, a file without any top-level import or export declarations is treated as a script whose contents are available in the global scope (and therefore to modules as well).

(出自 typesript > modules > introduction

// a.ts
const resolve = require('path').resolve

module.exports = {
  resolve
}
// b.ts
const { resolve } = require('./a') // 报错
// 在当前模块没有 `import` 或 `export` 关键词时,ts 编译器认为当前作用域与 a.ts 在同一作用域中
// 即使真实情况是,他们二者是属于不同的作用域

解决方案是 重命名 目标变量。

或者如同下面的示例代码一样,导出一个空对象(推荐解决方案)。

export {}

Reference

报错:在 window[this.property] 中,该属性值隐式地具有 any 类型。

此处有两个要点:

  1. 全局变量 window 对象已经声明

  2. 要指定的属性是 动态键名 的值。

    • 因为是动态键值故无法使用以下方法声明新添加的这个键名的值的类型:
// 只适用给固定键名的属性声明类型
// window 对象的类型是 Window 类型,注意大写
declare global {
  interface Window {
    name: string
  }
}
// 以上利用的原理是接口合并,将新的 Window 接口与默认 Window 接口类型合并
// details: https://www.typescriptlang.org/docs/handbook/declaration-merging.html
  1. 解决方案如下:
(<any>window)[this.property] = something
// 或者
(window as any)[this.property] = something

示例中 (<any>window) 中的 <any> 表示将 window 对象的类型强制转换为 any 类型,那么此时 window 上的所有属性类型值均转换为了 any 类型, 这里可理解为不需要 ts 来进行类型推断。注意,此处是属于 显式 指定 any 类型来解决报错。

暂无不转换 window 对象类型的解决方案。

报错:无 setTimeout,无 window 等浏览器端的常用全局变量。

{
  "compilerOptions": {
    "lib": ["dom"],
  }
}

报错: 在获取如同 setTimeout 的 ID 时报错 Timer 类型不能赋值给 number 类型。

原因是 setTimeout 等相关函数默认解析为 NodeJS.Timer 类型。

// 方法 1 ,显式调用 window 下的相关函数
let id: number = 0
id = window.setTimeout(() => {})

// 方法 2 , 声明变量为 NodeJS.Timer 类型
// https://nodejs.org/api/timers.html
let id: NodeJS.Timer

id = setTimeout(() => {})
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["es2015"],
  }
}

在配置声明文件 @types/node 之后,仍然报错 'Can't find name require'

可能的原因有:

  1. 报错的 ts 文件不在 tsconfig.jsoninclude 字段下的路径内。
lbwa commented 6 years ago

Vue.js

interface commit {
  commit: (info: string, payload?: any) => void
}

export const doSomething: (commit: commit) => void = ({ commit }) => {
  commit('doWhatYouWant')
}
lbwa commented 6 years ago

Node.js

yarn add @types/node -D

在安装 @types/node 后,以下是可选配置,不写的话 VS CODE 会默认在 node_modules@types 文件夹下查找模块声明。

{
  "compilerOptions":{
+    "types": [
+      "node"
+    ]
  }
}
const http = require('http')
import { ServerResponse, ServerRequest } from 'http'

const PORT = process.env.PORT || 8800

const server = http.createServer((req: ServerResponse, res: ServerRequest) => {
  // ...
})
server.listen(PORT)
lbwa commented 5 years ago

as 操作符、<AnyType> 尖括号操作符

ref: Official site

const foo = <foo>bar

以上代码表示一种类型断言 type assertion,该断言表示 bar 变量拥有类型 foo。因为 TypeScript 使用尖括号来表示类型断言 type assertion,而在 JSX 中使用这种尖括号表示类型断言将会造成一些解析困难(无法正确解析是 JSX 元素还是 类型断言)。所以,TypeScript 不允许在 .tsx 文件中使用尖括号这种类型断言。

as 作为一种可选的类型断言操作符应在 .tsx 文件中被使用。以上的示例可用 as 操作符来重写:

const foo = bar as foo

as 操作符可同时在 .ts.tsx 文件中使用,并且在行为上可尖括号类型断言相同。

lbwa commented 5 years ago

类型别名 —— type 关键字

ref: Official site