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

Javascript 我们可以在Typescript声明文件中使用全局符号吗?,javascript,typescript,global-variables,global,typescript-declarations,Javascript,Typescript,Global Variables,Global,Typescript Declarations,我正在尝试实现类似的东西,但我不确定这是否可能。我认为Typescript只允许使用唯一的符号,而不允许使用全局符号。这是正确的吗 有没有更好的方法来实现使用全局符号 // sample.d.ts const mySymbol = Symbol.for('internal.symbol') interface Sample{ [mySymbol]: string a: number b: number } // sample.js class SampleClass

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

您可以导出符号,即

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

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

以下是我如何做到这一点的

// 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=Sample
export as namespace Sample
专门导出它。看

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

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

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

有两种方法可以创建符号:

第一种方式
符号(助记符?:字符串)
,例如

const x = Symbol('optional name')
const y = Symbol('optional name')
assert(x!==y) // pass
每次调用
Symbol(…)
都会创建一个唯一的符号。
助记符
只是调试等的便利属性。 两个符号可以具有相同的助记符,而不是相同的符号

console.log(x.toString()) // 'Symbol(optional name)'
assert(x.toString()===y.toString()) // pass
assert(x!==y) // pass
当符号以这种方式创建时,它们只在用户代码中引用时才存在——就像其他对象一样,它们可以被垃圾收集

第二种方式
符号。用于(globalKey:string)
,例如

const x = Symbol('optional name')
const y = Symbol('optional name')
assert(x!==y) // pass
在文件“x.js”中,没有任何
import
/
require
语句

const x = Symbol.for('my.global.symbols.1')
export x
const x = Symbol.for('my.global.symbols.1')
export y
在文件“y.js”中,没有任何
import
/
require
语句

const x = Symbol.for('my.global.symbols.1')
export x
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的内容:

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

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

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

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


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

我希望从.d.ts文件(如类型或接口)执行此操作。但它似乎必须从常规的.ts文件导出,然后导入到.d.ts文件中?是吗?@tagyoureit d.ts文件是编译您的TypeScript文件的产品,您不应该在开发过程中直接使用它们。..d.ts文件是声明文件,在TypeScript中非常标准()是的,它们是标准的,但是在实践中,当使用捆绑程序(如webpack)时,您不需要直接使用d.ts文件。另见。我想如果你没有使用bundler,我可以理解你为什么要问这个问题。没错,我没有使用Webpack和声明文件来确保我应用程序不同部分的一致性。但你的回答确实帮助我找到了一些可行的方法。我会把它贴在下面。谢谢。这就是我在回答中所说的。导出符号,然后将其导入任何需要的文件。是的,谢谢。我仍然需要对实现进行一些挣扎(下次代码示例会更好),所以我在这里记录了它,以便其他人轻松地重新创建。