Open lbwa opened 6 years ago
xxx
。TS2451: Cannot redeclare block-scoped variable 'xxx'
在排除当前模块中不存在同名属性之后仍报错。
原因:在 ts 中,若当前文件中未出现 import
或 export
关键词时,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 {}
window[this.property]
中,该属性值隐式地具有 any
类型。此处有两个要点:
全局变量 window
对象已经声明
要指定的属性是 动态键名 的值。
// 只适用给固定键名的属性声明类型
// window 对象的类型是 Window 类型,注意大写
declare global {
interface Window {
name: string
}
}
// 以上利用的原理是接口合并,将新的 Window 接口与默认 Window 接口类型合并
// details: https://www.typescriptlang.org/docs/handbook/declaration-merging.html
(<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(() => {})
Promise
仅为类型,不能直接使用。{
"compilerOptions": {
"target": "es5",
"lib": ["es2015"],
}
}
@types/node
之后,仍然报错 'Can't find name require
'可能的原因有:
ts
文件不在 tsconfig.json
中 include
字段下的路径内。vuex
中 actions
的 commit
接口interface commit {
commit: (info: string, payload?: any) => void
}
export const doSomething: (commit: commit) => void = ({ commit }) => {
commit('doWhatYouWant')
}
nodejs
中 CommonJS
的 module
, require
等对象的声明yarn add @types/node -D
在安装 @types/node
后,以下是可选配置,不写的话 VS CODE
会默认在 node_modules
的 @types
文件夹下查找模块声明。
{
"compilerOptions":{
+ "types": [
+ "node"
+ ]
}
}
nodejs
中的 request
和 response
对象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)
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
文件中使用,并且在行为上可尖括号类型断言相同。
type
关键字ref: Official site
使用技巧
定义时
确定类型,而在运行时
确定类型。泛型的出现允许我们跟踪函数内的变量类型信息。注:在泛型的类型未确定时,不能调用有关参数的属性(即泛型约束)。