简体   繁体   English

如何在编译时捕获子类型到超类型的分配?

[英]How to catch at compile-time an assignment of a subtype to a supertype?

I learnt that the 了解到

rule for TypeScript's structural type system is that x is compatible with y if y has at least the same members as x 为打字稿的结构类型系统的规则是, x是兼容y如果y具有至少相同的部件x

This allows an assignment of a variable of a subtype to a variable of a supertype. 这允许将子类型的变量分配给超类型的变量。 Is there a way to get a compile-time error regarding that assignment? 有没有办法得到关于该分配的编译时错误?

( TypeScript Playground ) TypeScript游乐场

interface SuperT {
    field: string
}

// an explicitly declared subtype object for a supertype variable generates an error
const super1: SuperT = {field: 'value', extra: 1} // compile-time error: Type '{ field: string; extra: number; }' is not assignable to type 'SuperT'

function subTValue() { return {field: 'value', extra: 1} }
const super2: SuperT = subTValue() // no compile-time error, BUT HOW TO get a compile-time error here? 

You want exact types which aren't directly supported. 您需要不直接支持的确切类型 You can do various tricks with generics and conditional types to get closer. 您可以使用泛型和条件类型来做各种技巧,以更进一步 Here's one way to do it indirectly: 这是间接执行此操作的一种方法:

interface SuperT {
    field: string
}

type Exactly<T, U extends T> = T & Record<Exclude<keyof U, keyof T>, never>;
const asExactlySuperT = <U extends Exactly<SuperT, U>>(superT: U) => superT;

const superOkay: SuperT = asExactlySuperT({ field: "a" }); // okay

function subTValue() { return { field: 'value', extra: 1 } }
const superBad: SuperT = asExactlySuperT(subTValue()); // error! 
// types of property "extra" are incompatible

Link to code 链接到代码

The idea there is that Exactly<T, U> will take a type T and a candidate type U which hopefully matches T exactly with no extra properties. 这里的想法是, Exactly<T, U>将采用类型T和候选类型U ,希望该类型与T完全匹配而没有任何额外的属性。 If it does, then Exactly<T, U> will equal U . 如果是这样,则Exactly<T, U>将等于U If it does not, then Exactly<T, U> will set the property types of any extra properties to never . 如果不是,则Exactly<T, U>会将任何其他属性的属性类型设置为never Since asExactlySuperT<U>() requires that U extends Exactly<SuperT, U> , the only way that can happen is if there are no extra properties in U . 由于asExactlySuperT<U>()需要U extends Exactly<SuperT, U> ,因此唯一可能发生的方法是在U中没有额外的属性。

Hope that helps. 希望能有所帮助。 Good luck! 祝好运!

As Ray Toal found out, an answer for a very similar issue can be found here . 正如雷·托尔(Ray Toal)所发现的,可以在这里找到非常相似的问题的答案。 (And I knew this in the first place, I just wanted to check jcalz 's reaction time. Pretty impressive, @jcalz!) (我一开始就知道这一点,我只是想检查jcalz的反应时间。非常棒,@ jcalz!)

Based on that approach, my code would look like: 基于这种方法,我的代码如下所示:

( TypeScript Playground ) TypeScript游乐场

type StrictPropertyCheck<T, TExpected, TError> = Exclude<keyof T, keyof TExpected> extends never ? {} : TError

interface SuperT {
    field: string
}

function doIdentity<T extends SuperT>(a: T & StrictPropertyCheck<T, SuperT, "Only allowed properties of SuperT">) {
    return a
}


function subTValue() { return { field: 'value', extra: 1 } }

const super3: SuperT = doIdentity(subTValue()) // we do get a compile-time error!

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

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