简体   繁体   English

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

[英]Can we use global symbols in Typescript Declaration files?

I'm trying to implement something like this but I'm not sure it's possible.我正在尝试实现这样的东西,但我不确定这是否可能。 I think Typescript only allows unique symbols, not global ones.我认为 Typescript 只允许唯一的符号,而不是全局符号。 Is this correct?这样对吗?

Is there a better way to achieve using global symbols?有没有更好的方法来实现使用全局符号?

// 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)

Is there a way to accomplish this?有没有办法做到这一点? mySymbol can (and ideally will) be a global symbol that will be used by other objects as well so it can be defined separately if that can be accomplished. mySymbol可以(并且理想情况下)是其他对象也将使用的全局符号,因此如果可以实现,可以单独定义它。

Here is how I was able to accomplish this.这是我如何能够做到这一点。

// 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)

Once mySymbol is imported into the declaration file it turns into a module.一旦mySymbol被导入到声明文件中,它就会变成一个模块。 Hence it needs to be specifically exported with the export = Sample and export as namespace Sample .因此,它需要使用export = Sample专门导出,并export as namespace Sample See sample module.d.ts .请参阅示例 module.d.ts

You can export your symbol ie您可以导出您的符号,即

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

and then import it into whatever file requires it.然后将其导入到任何需要它的文件中。 This way you won't pollute the global scope and you can import it only when necessary.这样您就不会污染全局范围,并且您可以仅在必要时导入它。

... I think Typescript only allows unique symbols, not global ones. ...我认为 Typescript 只允许唯一的符号,而不是全局符号。 Is this correct?这样对吗?

All symbols are unique.所有符号都是唯一的。 That is invariant.那是不变的。

How to scope and access symbols is another question.如何范围和访问符号是另一个问题。

There are two ways to create symbols:有两种方法可以创建符号:

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

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

Every call to Symbol(...) creates a unique symbol.每次调用Symbol(...)都会创建一个唯一的符号。 The mnemonic is just a convenience property for debugging, etc. Two symbols can have the same mnemonic without being the same symbol. mnemonic只是用于调试等的便利属性。两个符号可以具有相同的助记符而不是相同的符号。

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

When symbols are created in this way they only exist as long as they are referenced in user code - just like other objects, they can be garbage collected.当以这种方式创建符号时,它们仅在用户代码中引用时才存在 - 就像其他对象一样,它们可以被垃圾收集。

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

In file 'x.js', with NO import / require statements at all在文件“x.js”中,根本没有import / require语句

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

In file 'y.js', with NO import / require statements at all在文件“y.js”中,根本没有import / require语句

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

In file 'z.js'在文件“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

In this case, a unique global symbol is created for each UNIQUE global key passed as the globalKey parameter to Symbol.for(globalKey:string) - from any file.在这种情况下,为作为globalKey参数传递给Symbol.for(globalKey:string)每个 UNIQUE 全局键创建一个唯一的全局符号 - 从任何文件。 The symbol instance is stored in opaque global space, as though there were an opaque global map:符号实例存储在不透明的全局空间中,就好像有一个不透明的全局映射:

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

(although that might not be how it is actually implemented). (虽然这可能不是它实际实施的方式)。

Here is what MDN says about Symbol.for() :以下是 MDN 关于Symbol.for()

In contrast to Symbol(), the Symbol.for() function creates a symbol available in a global symbol registry list.与 Symbol() 不同,Symbol.for() 函数在全局符号注册表列表中创建一个可用的符号。 Symbol.for() does also not necessarily create a new symbol on every call, but checks first if a symbol with the given key is already present in the registry. Symbol.for() 也不一定在每次调用时都创建一个新符号,但首先检查具有给定键的符号是否已存在于注册表中。 In that case, that symbol is returned.在这种情况下,将返回该符号。 If no symbol with the given key is found, Symbol.for() will create a new global symbol.如果没有找到具有给定键的符号,Symbol.for() 将创建一个新的全局符号。

About garbage collection for these globally managed symbols - I don't know which of the following are true:关于这些全局管理符号的垃圾收集 - 我知道以下哪些是正确的:

  • When a globally managed symbol is no longer referenced by any user code (ie, not including the reference from the opaque global 'virtual' map) then it may be garbage collected.当一个全局管理的符号不再被任何用户代码引用时(即,不包括来自不透明全局“虚拟”映射的引用),那么它可能会被垃圾收集。

  • Once created, globally managed symbols remain in the opaque global 'virtual' map until end of program life.创建后,全局管理的符号将保留在不透明的全局“虚拟”映射中,直到程序生命周期结束。

From the perspective of user code 'logic', there would be no difference between the two - it's entirely an implementation issue.从用户代码“逻辑”的角度来看,两者之间没有区别——这完全是一个实现问题。 However, performance, including memory usage, would differ.但是,性能(包括内存使用情况)会有所不同。 My guess is that some garbage collection is enabled.我的猜测是启用了一些垃圾收集。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM