我可以强制TypeScript编译器使用标称类型吗?

我可以强制TypeScript编译器使用标称类型吗?,typescript,duck-typing,Typescript,Duck Typing,TypeScript使用,因此这实际上是可能的: // there is a class class MyClassTest { foo():void{} bar():void{} } // and a function which accepts instances of that class as a parameter function someFunction(f:MyClassTest):void{ if (f){ if (!(f instan

TypeScript使用,因此这实际上是可能的:

// there is a class
class MyClassTest {
    foo():void{}
    bar():void{}
}

// and a function which accepts instances of that class as a parameter
function someFunction(f:MyClassTest):void{
    if (f){
        if (!(f instanceof MyClassTest)) {
            console.log("why")
        } 
    }
}

// but it's valid to pass objects, which aren't in fact instances
// they just need to "look" the same, be "structural subtypes"
someFunction({foo(){}, bar(){}})  //valid!
然而,作为
someFunction
的实现提供者,我确实希望禁止传递结构相似的对象,但我只希望允许MyClassTest或其子类型的真实实例。我希望至少对我自己的一些函数声明强制执行“标称类型”

这可能吗

背景:考虑一个传递给API的对象需要是那种类型的例子,例如,它们是由一个工厂生成的,该工厂在这个对象上设置一些内部状态,并且对象实际上有一个私有接口,<>代码>某个函数< /代码>期望在那里,以便正常工作。但是,我不想透露这个私有接口(例如,在typescript定义文件中),但如果有人传入了一个伪实现,我希望它是一个编译器错误。具体示例:我希望typescript编译器在这种情况下抱怨,即使我提供的所有成员都是这样:

//OK for typescript, breaks at runtime
window.document.body.appendChild({nodeName:"div", namespaceURI:null, ...document.body}) 

没有编译器标志使编译器以一种名义上的方式运行,实际上原则上不可能有这样一个标志,因为它会破坏许多javascript场景

有几种技术通常用于模拟某种类型的命名类型。品牌类型通常用于原语(从中选择一个作为示例),对于类,常见的方法是添加一个私有字段(私有字段在结构上不会与任何内容匹配,除非精确的私有字段定义)

使用最后一种方法,您的初始样本可以写成:

// there is a class
class MyClassTest {
    private _useNominal: undefined; // private field to ensure nothing else is structually compatible.
    foo():void{}
    bar():void{}
}

// and a function which accepts instances of that class as a parameter
function someFunction(f:MyClassTest):void{
    if (f){
        if (!(f instanceof MyClassTest)) {
            console.log("why")
        } 
    }
}


someFunction({foo(){}, bar(){}, _useNominal: undefined})  //err

对于使用
append
的特定场景,我认为我们无法做任何我们能做的事情,因为
Node
lib.d.ts
中定义为一个接口和一个
const
,所以用一个私有字段来扩充它几乎是不可能的(不更改
lib.d.ts
),即使我们可以,它也可能会破坏许多现有的代码和定义

谢谢!我实际上并不是在寻找全局编译器标志。很明显,这样的标志可能会破坏很多代码。我希望能够在参数类型中添加某种修饰符(比如
someFunction(f:MyClassTest!)
)来更改该方法的行为。“private”黑客很酷-但我想它在类型定义文件中不起作用,因为在类型定义文件中,私有定义没有什么意义。@Sebastian您可以在声明中使用私有字段,这没有问题,因为TS需要了解私有以防止意外重写。但在这种情况下,没有办法增加现有的定义。实际上,像
strictNullChecks
=>
nominalTypeChecks
这样的全局(opt-in)标志是可行的,我想-我不相信它会比
strictNullCheck
破坏更多的代码<代码>接口仍然是鸭子类型的。我不认为这些假类被如此频繁地使用。