【问题标题】:Can we use global symbols in Typescript Declaration files?我们可以在 Typescript 声明文件中使用全局符号吗?
【发布时间】:2019-05-27 22:32:06
【问题描述】:

我正在尝试实现类似的东西,但我不确定它是否可能。我认为 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 可以(并且理想情况下)是一个全局符号,其他对象也将使用它,因此如果可以实现,它可以单独定义。

【问题讨论】:

    标签: javascript typescript global-variables global typescript-declarations


    【解决方案1】:

    这是我能够做到这一点的方法。

    // 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】:

    您可以导出您的符号,即

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

    然后将其导入到需要它的任何文件中。这样就不会污染全局作用域,只有在必要时才可以导入。

    【讨论】:

    • 我希望从 .d.ts 文件(如类型或接口)中执行此操作。但它似乎必须从常规的 .ts 文件中导出,然后导入到 .d.ts 中?对吗?
    • @tagyoureit d.ts 文件是编译你的 TypeScript 文件的产物,你不应该在开发过程中直接使用它们。
    • .d.ts 文件是声明文件,在 TypeScript 中非常标准 (typescriptlang.org/docs/handbook/declaration-files/…)
    • 是的,它们是标准的,但实际上在使用 webpack 之类的打包程序时,您不需要直接使用 d.ts 文件。另见here。我想如果您不使用捆绑程序,我可以理解您为什么要问这个问题。
    • 正确,我没有使用 Webpack,而是使用声明文件来确保应用程序不同部分的一致性。但是您的回答确实帮助我找到了可行的方法。我将在下面发布。谢谢。
    【解决方案3】:

    ...我认为 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) 的每个唯一全局键创建一个唯一全局符号。 符号实例存储在不透明的全局空间中,就好像有一个不透明的全局地图:

    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() 将创建一个新的全局符号。

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2011-05-14
      • 2013-09-20
      • 2017-06-06
      • 2011-05-09
      • 2022-01-22
      • 2020-11-22
      • 2018-07-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多