我们可以在Typescript声明文件中使用全局符号吗?

时间:2019-05-27 22:32:06

标签: javascript typescript

我正在尝试实现类似的方法,但是我不确定是否有可能。我认为Typescript仅允许使用唯一的符号,而不能使用全局符号。这是正确的吗?

是否有更好的方法来使用全局符号?

// sample.d.ts
const mySymbol = Symbol.for('internal.symbol')

interface Sample{
    [mySymbol]: string
    a: number
    b: number
}

// sample.js
class SampleClass implements Sample {
    [mySymbol]: string
    a: number
    b: number

    constructor(a: number, b: number){
        this.a = a;
        this.b = b;
        this[mySymbol] = `${a}-${b}`
    }
}

let mySample = new SampleClass(1, 2)

有没有办法做到这一点? mySymbol可以(并且理想情况下将是)其他对象也将使用的全局符号,因此如果可以实现,则可以单独定义它。

3 个答案:

答案 0 :(得分:0)

您可以导出符号,即

export const mySymbol = Symbol.for('internal.symbol')

,然后将其导入任何需要的文件中。这样,您就不会污染全局范围,并且只有在必要时才可以导入它。

答案 1 :(得分:0)

这就是我能够完成此操作的方式。

// misc.ts
export const mySymbol = Symbol.for('internal.symbol')

// sample.d.ts
import {mySymbol} from './misc'

export as namespace Sample
export = Sample
interface Sample{
    [mySymbol]: string
    a: number
    b: number
}

// sample.js
class SampleClass implements Sample {
    [mySymbol]: string
    a: number
    b: number

    constructor(a: number, b: number){
        this.a = a;
        this.b = b;
        this[mySymbol] = `${a}-${b}`
    }
}

let mySample = new SampleClass(1, 2)

一旦mySymbol被导入到声明文件中,它将变成一个模块。因此,需要使用export = Sampleexport as namespace Sample专门导出它。参见sample module.d.ts

答案 2 :(得分:0)

<块引用>

... 我认为 Typescript 只允许唯一的符号,而不是全局的。这是正确的吗?

所有符号都是唯一的。这是不变的。

如何界定和访问符号是另一个问题。

有两种创建符号的方法:

第一种方式Symbol(mnemonic?:string),例如

const x = Symbol('optional name')
const y = Symbol('optional name')
assert(x!==y) // pass

每次调用 Symbol(...) 都会创建一个独特的符号。 mnemonic 只是用于调试等的便利属性。 两个符号可以具有相同的助记符而不是相同的符号。

console.log(x.toString()) // 'Symbol(optional name)'
assert(x.toString()===y.toString()) // pass
assert(x!==y) // pass

当以这种方式创建符号时,它们只会在用户代码中被引用时才存在 - 就像其他对象一样,它们可以被垃圾回收。

第二种方式Symbol.for(globalKey:string),例如

在文件“x.js”中,根本没有 import/require 语句

const x = Symbol.for('my.global.symbols.1')
export x

在文件 'y.js' 中,根本没有 import/require 语句

const x = Symbol.for('my.global.symbols.1')
export y

在文件“z.js”中

import {x} from './x'
import {y} from './y'
assert(x===y) // pass
const z = Symbol.for('my.global.symbols.1')
assert(x===z) // pass

在这种情况下,为从任何文件中作为 globalKey 参数传递给 Symbol.for(globalKey:string) 的每个 UNIQUE 全局键创建一个唯一的全局符号。 符号实例存储在不透明的全局空间中,就好像有一个不透明的全局映射:

Symbol.for(globalKey:string):symbol{
  if (globalSymbolMap.has(globalKey)
    return globalSymbolMap.get(globalKey)
  else{
    const s=Symbol(globalKey)
    globalSymbolMap.set(globalKey,s)
    return s
  }
}

(虽然这可能不是它实际实现的方式)。

这是 MDN says about Symbol.for()

<块引用>

与 Symbol() 相比,Symbol.for() 函数在全局符号注册表列表中创建一个可用的符号。 Symbol.for() 也不一定在每次调用时都创建一个新符号,但首先检查具有给定键的符号是否已存在于注册表中。在这种情况下,将返回该符号。如果没有找到具有给定键的符号,Symbol.for() 将创建一个新的全局符号。

关于这些全局管理符号的垃圾收集 - 我知道以下哪些是正确的:

  • 当一个全局管理的符号不再被任何用户代码引用(即,不包括来自不透明全局“虚拟”映射的引用)时,它可能会被垃圾回收。< /p>

  • 创建后,全局管理的符号将保留在不透明的全局“虚拟”映射中,直到程序生命周期结束。

从用户代码“逻辑”的角度来看,两者之间没有区别 - 这完全是一个实现问题。但是,性能(包括内存使用情况)会有所不同。我的猜测是启用了一些垃圾收集。