TypeScript extra keys in nested objectsWhat is TypeScript and why would I use it in place of JavaScript?How do you explicitly set a new property on `window` in TypeScript?Type definition in object literal in TypeScriptget and set in TypeScriptHow can I create an object based on an interface file definition in TypeScript?TypeScript Objects as Dictionary types as in C#Are strongly-typed functions as parameters possible in TypeScript?TypeScript Converting a String to a numberHow do I cast a JSON object to a typescript classTypescript: Interfaces vs Types

Impact of throwing away fruit waste on a peak > 3200 m above a glacier

How do I run a game when my PCs have different approaches to combat?

How can I deal with someone that wants to kill something that isn't supposed to be killed?

Is the apartment I want to rent a scam?

Sometimes you are this word with three vowels

What's the 1 inch size square knob sticking out of wall?

what to say when a company asks you why someone (a friend) who was fired left?

Why are MEMS in QFN packages?

Can I pay with HKD in Macau or Shenzhen?

Is it OK to accept a job opportunity while planning on not taking it?

Raw curve25519 public key points

Are glider winch launches rarer in the USA than in the rest of the world? Why?

The seven story archetypes. Are they truly all of them?

Using "Kollege" as "university friend"?

Historicity doubted by Romans

What exactly makes a General Products hull nearly indestructible?

How to repair basic cable/wire issue for household appliances

What the purpose of the fuel shutoff valve?

Are gangsters hired to attack people at a train station classified as a terrorist attack?

Sextortion with actual password not found in leaks

Company requiring me to let them review research from before I was hired

What is an Eternal Word™?

Should i describe deeply a character before killing it?

What does the Find Familiar spell target?



TypeScript extra keys in nested objects


What is TypeScript and why would I use it in place of JavaScript?How do you explicitly set a new property on `window` in TypeScript?Type definition in object literal in TypeScriptget and set in TypeScriptHow can I create an object based on an interface file definition in TypeScript?TypeScript Objects as Dictionary types as in C#Are strongly-typed functions as parameters possible in TypeScript?TypeScript Converting a String to a numberHow do I cast a JSON object to a typescript classTypescript: Interfaces vs Types






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








2















My problem can be summed up with this little snippet (here's a larger, interactive example in the Playground):



type X = x: number;
type Y = y: number;
type XXY = x: X & Y;
let xxy: XXY =
x:
x: 1,
notValid: 1 // <--- this is not an error :(
,
y: 1
;


Given that X and Y are derived in another way (and so I can't just write the XXY type by hand), how can I make it so that unknown keys in the nested object are treated as invalid?










share|improve this question

















  • 1





    github.com/Microsoft/TypeScript/issues/18075

    – ritaj
    Mar 26 at 14:59











  • Interesting scenario. Also, it's interesting that if you remove y: 1, instead of complaining about y missing, it complains about notValid being invalid. prntscr.com/n36p0v

    – briosheje
    Mar 26 at 15:00

















2















My problem can be summed up with this little snippet (here's a larger, interactive example in the Playground):



type X = x: number;
type Y = y: number;
type XXY = x: X & Y;
let xxy: XXY =
x:
x: 1,
notValid: 1 // <--- this is not an error :(
,
y: 1
;


Given that X and Y are derived in another way (and so I can't just write the XXY type by hand), how can I make it so that unknown keys in the nested object are treated as invalid?










share|improve this question

















  • 1





    github.com/Microsoft/TypeScript/issues/18075

    – ritaj
    Mar 26 at 14:59











  • Interesting scenario. Also, it's interesting that if you remove y: 1, instead of complaining about y missing, it complains about notValid being invalid. prntscr.com/n36p0v

    – briosheje
    Mar 26 at 15:00













2












2








2








My problem can be summed up with this little snippet (here's a larger, interactive example in the Playground):



type X = x: number;
type Y = y: number;
type XXY = x: X & Y;
let xxy: XXY =
x:
x: 1,
notValid: 1 // <--- this is not an error :(
,
y: 1
;


Given that X and Y are derived in another way (and so I can't just write the XXY type by hand), how can I make it so that unknown keys in the nested object are treated as invalid?










share|improve this question














My problem can be summed up with this little snippet (here's a larger, interactive example in the Playground):



type X = x: number;
type Y = y: number;
type XXY = x: X & Y;
let xxy: XXY =
x:
x: 1,
notValid: 1 // <--- this is not an error :(
,
y: 1
;


Given that X and Y are derived in another way (and so I can't just write the XXY type by hand), how can I make it so that unknown keys in the nested object are treated as invalid?







typescript






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Mar 26 at 14:51









nickfnickf

386k175 gold badges592 silver badges692 bronze badges




386k175 gold badges592 silver badges692 bronze badges







  • 1





    github.com/Microsoft/TypeScript/issues/18075

    – ritaj
    Mar 26 at 14:59











  • Interesting scenario. Also, it's interesting that if you remove y: 1, instead of complaining about y missing, it complains about notValid being invalid. prntscr.com/n36p0v

    – briosheje
    Mar 26 at 15:00












  • 1





    github.com/Microsoft/TypeScript/issues/18075

    – ritaj
    Mar 26 at 14:59











  • Interesting scenario. Also, it's interesting that if you remove y: 1, instead of complaining about y missing, it complains about notValid being invalid. prntscr.com/n36p0v

    – briosheje
    Mar 26 at 15:00







1




1





github.com/Microsoft/TypeScript/issues/18075

– ritaj
Mar 26 at 14:59





github.com/Microsoft/TypeScript/issues/18075

– ritaj
Mar 26 at 14:59













Interesting scenario. Also, it's interesting that if you remove y: 1, instead of complaining about y missing, it complains about notValid being invalid. prntscr.com/n36p0v

– briosheje
Mar 26 at 15:00





Interesting scenario. Also, it's interesting that if you remove y: 1, instead of complaining about y missing, it complains about notValid being invalid. prntscr.com/n36p0v

– briosheje
Mar 26 at 15:00












1 Answer
1






active

oldest

votes


















1














This is a known bug where excess property checking doesn't apply to nested types involving unions and intersections in the way that people expect. Excess property checking is kind of an add-on to the type system that only applies to object literals, so when it doesn't apply, things fall back to the structural subtyping rule where type a: A, b: B is a subtype of a: A, and so a value of the former type should be assignable to a variable of the latter type. You might want to head over to the issue in Github and give it a 👍 or explain your use case if you think it's more compelling than the ones already listed there. Hopefully there will be a fix someday.



Until then, there are workarounds. The type-level equivalent to excess property checks are so-called exact types, which don't exist in TypeScript as concrete types. There are ways to simulate them using generic helper functions and type inference... in your case it would look something like this:



type Exactly<T, U extends T> = T extends object ?
[K in keyof U]: K extends keyof T ? Exactly<T[K], U[K]> : never
: T

const asXXY = <T extends XXY>(x: T & Exactly<XXY, T>): T => x;

let xxy = asXXY(
x:
x: 1,
notValid: 1 // error!
,
y: 1
);


That's the error you want, right?



How it works: The helper function asXXY<T extends XXY>(t: T & Exactly<XXY, T>) infers the generic type T to be the type of the passed-in parameter t. Then it tries to evaluate the intersection T & Exactly<XXY, T>. If t is assignable to T & Exactly<XXY, T>, the check succeeds and the function is callable. Otherwise, there will be an error somewhere on t showing where they differ.



And Exactly<T, U extends T> basically walks down recursively through U, keeping it the same as long as it matches T... otherwise it sets the property to never.



Let's expand on this difference for the above case: The inferred type for T was



 x: x: number; notValid: number; ; y: number; 


Is that assignable to T & Exactly<XXY, T>? Well, what's Exactly<XXY, T>? It's turns out to be



 x: x: number; notValid: never; ; y: number; 


which is what happens when you drill down into type T and notice that notValid can't be found inside XXY.



The intersection T & Exactly<XXY, T> is essentially just Exactly<XXY, T>, so now the compiler is comparing the passed-in parameter to the type



 x: x: number; notValid: never; ; y: number; 


which it isn't. The notValid type is a number, not a never... so the compiler complains in exactly the place you want.



Okay, hope that helps. Good luck!






share|improve this answer






















    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55360087%2ftypescript-extra-keys-in-nested-objects%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    This is a known bug where excess property checking doesn't apply to nested types involving unions and intersections in the way that people expect. Excess property checking is kind of an add-on to the type system that only applies to object literals, so when it doesn't apply, things fall back to the structural subtyping rule where type a: A, b: B is a subtype of a: A, and so a value of the former type should be assignable to a variable of the latter type. You might want to head over to the issue in Github and give it a 👍 or explain your use case if you think it's more compelling than the ones already listed there. Hopefully there will be a fix someday.



    Until then, there are workarounds. The type-level equivalent to excess property checks are so-called exact types, which don't exist in TypeScript as concrete types. There are ways to simulate them using generic helper functions and type inference... in your case it would look something like this:



    type Exactly<T, U extends T> = T extends object ?
    [K in keyof U]: K extends keyof T ? Exactly<T[K], U[K]> : never
    : T

    const asXXY = <T extends XXY>(x: T & Exactly<XXY, T>): T => x;

    let xxy = asXXY(
    x:
    x: 1,
    notValid: 1 // error!
    ,
    y: 1
    );


    That's the error you want, right?



    How it works: The helper function asXXY<T extends XXY>(t: T & Exactly<XXY, T>) infers the generic type T to be the type of the passed-in parameter t. Then it tries to evaluate the intersection T & Exactly<XXY, T>. If t is assignable to T & Exactly<XXY, T>, the check succeeds and the function is callable. Otherwise, there will be an error somewhere on t showing where they differ.



    And Exactly<T, U extends T> basically walks down recursively through U, keeping it the same as long as it matches T... otherwise it sets the property to never.



    Let's expand on this difference for the above case: The inferred type for T was



     x: x: number; notValid: number; ; y: number; 


    Is that assignable to T & Exactly<XXY, T>? Well, what's Exactly<XXY, T>? It's turns out to be



     x: x: number; notValid: never; ; y: number; 


    which is what happens when you drill down into type T and notice that notValid can't be found inside XXY.



    The intersection T & Exactly<XXY, T> is essentially just Exactly<XXY, T>, so now the compiler is comparing the passed-in parameter to the type



     x: x: number; notValid: never; ; y: number; 


    which it isn't. The notValid type is a number, not a never... so the compiler complains in exactly the place you want.



    Okay, hope that helps. Good luck!






    share|improve this answer



























      1














      This is a known bug where excess property checking doesn't apply to nested types involving unions and intersections in the way that people expect. Excess property checking is kind of an add-on to the type system that only applies to object literals, so when it doesn't apply, things fall back to the structural subtyping rule where type a: A, b: B is a subtype of a: A, and so a value of the former type should be assignable to a variable of the latter type. You might want to head over to the issue in Github and give it a 👍 or explain your use case if you think it's more compelling than the ones already listed there. Hopefully there will be a fix someday.



      Until then, there are workarounds. The type-level equivalent to excess property checks are so-called exact types, which don't exist in TypeScript as concrete types. There are ways to simulate them using generic helper functions and type inference... in your case it would look something like this:



      type Exactly<T, U extends T> = T extends object ?
      [K in keyof U]: K extends keyof T ? Exactly<T[K], U[K]> : never
      : T

      const asXXY = <T extends XXY>(x: T & Exactly<XXY, T>): T => x;

      let xxy = asXXY(
      x:
      x: 1,
      notValid: 1 // error!
      ,
      y: 1
      );


      That's the error you want, right?



      How it works: The helper function asXXY<T extends XXY>(t: T & Exactly<XXY, T>) infers the generic type T to be the type of the passed-in parameter t. Then it tries to evaluate the intersection T & Exactly<XXY, T>. If t is assignable to T & Exactly<XXY, T>, the check succeeds and the function is callable. Otherwise, there will be an error somewhere on t showing where they differ.



      And Exactly<T, U extends T> basically walks down recursively through U, keeping it the same as long as it matches T... otherwise it sets the property to never.



      Let's expand on this difference for the above case: The inferred type for T was



       x: x: number; notValid: number; ; y: number; 


      Is that assignable to T & Exactly<XXY, T>? Well, what's Exactly<XXY, T>? It's turns out to be



       x: x: number; notValid: never; ; y: number; 


      which is what happens when you drill down into type T and notice that notValid can't be found inside XXY.



      The intersection T & Exactly<XXY, T> is essentially just Exactly<XXY, T>, so now the compiler is comparing the passed-in parameter to the type



       x: x: number; notValid: never; ; y: number; 


      which it isn't. The notValid type is a number, not a never... so the compiler complains in exactly the place you want.



      Okay, hope that helps. Good luck!






      share|improve this answer

























        1












        1








        1







        This is a known bug where excess property checking doesn't apply to nested types involving unions and intersections in the way that people expect. Excess property checking is kind of an add-on to the type system that only applies to object literals, so when it doesn't apply, things fall back to the structural subtyping rule where type a: A, b: B is a subtype of a: A, and so a value of the former type should be assignable to a variable of the latter type. You might want to head over to the issue in Github and give it a 👍 or explain your use case if you think it's more compelling than the ones already listed there. Hopefully there will be a fix someday.



        Until then, there are workarounds. The type-level equivalent to excess property checks are so-called exact types, which don't exist in TypeScript as concrete types. There are ways to simulate them using generic helper functions and type inference... in your case it would look something like this:



        type Exactly<T, U extends T> = T extends object ?
        [K in keyof U]: K extends keyof T ? Exactly<T[K], U[K]> : never
        : T

        const asXXY = <T extends XXY>(x: T & Exactly<XXY, T>): T => x;

        let xxy = asXXY(
        x:
        x: 1,
        notValid: 1 // error!
        ,
        y: 1
        );


        That's the error you want, right?



        How it works: The helper function asXXY<T extends XXY>(t: T & Exactly<XXY, T>) infers the generic type T to be the type of the passed-in parameter t. Then it tries to evaluate the intersection T & Exactly<XXY, T>. If t is assignable to T & Exactly<XXY, T>, the check succeeds and the function is callable. Otherwise, there will be an error somewhere on t showing where they differ.



        And Exactly<T, U extends T> basically walks down recursively through U, keeping it the same as long as it matches T... otherwise it sets the property to never.



        Let's expand on this difference for the above case: The inferred type for T was



         x: x: number; notValid: number; ; y: number; 


        Is that assignable to T & Exactly<XXY, T>? Well, what's Exactly<XXY, T>? It's turns out to be



         x: x: number; notValid: never; ; y: number; 


        which is what happens when you drill down into type T and notice that notValid can't be found inside XXY.



        The intersection T & Exactly<XXY, T> is essentially just Exactly<XXY, T>, so now the compiler is comparing the passed-in parameter to the type



         x: x: number; notValid: never; ; y: number; 


        which it isn't. The notValid type is a number, not a never... so the compiler complains in exactly the place you want.



        Okay, hope that helps. Good luck!






        share|improve this answer













        This is a known bug where excess property checking doesn't apply to nested types involving unions and intersections in the way that people expect. Excess property checking is kind of an add-on to the type system that only applies to object literals, so when it doesn't apply, things fall back to the structural subtyping rule where type a: A, b: B is a subtype of a: A, and so a value of the former type should be assignable to a variable of the latter type. You might want to head over to the issue in Github and give it a 👍 or explain your use case if you think it's more compelling than the ones already listed there. Hopefully there will be a fix someday.



        Until then, there are workarounds. The type-level equivalent to excess property checks are so-called exact types, which don't exist in TypeScript as concrete types. There are ways to simulate them using generic helper functions and type inference... in your case it would look something like this:



        type Exactly<T, U extends T> = T extends object ?
        [K in keyof U]: K extends keyof T ? Exactly<T[K], U[K]> : never
        : T

        const asXXY = <T extends XXY>(x: T & Exactly<XXY, T>): T => x;

        let xxy = asXXY(
        x:
        x: 1,
        notValid: 1 // error!
        ,
        y: 1
        );


        That's the error you want, right?



        How it works: The helper function asXXY<T extends XXY>(t: T & Exactly<XXY, T>) infers the generic type T to be the type of the passed-in parameter t. Then it tries to evaluate the intersection T & Exactly<XXY, T>. If t is assignable to T & Exactly<XXY, T>, the check succeeds and the function is callable. Otherwise, there will be an error somewhere on t showing where they differ.



        And Exactly<T, U extends T> basically walks down recursively through U, keeping it the same as long as it matches T... otherwise it sets the property to never.



        Let's expand on this difference for the above case: The inferred type for T was



         x: x: number; notValid: number; ; y: number; 


        Is that assignable to T & Exactly<XXY, T>? Well, what's Exactly<XXY, T>? It's turns out to be



         x: x: number; notValid: never; ; y: number; 


        which is what happens when you drill down into type T and notice that notValid can't be found inside XXY.



        The intersection T & Exactly<XXY, T> is essentially just Exactly<XXY, T>, so now the compiler is comparing the passed-in parameter to the type



         x: x: number; notValid: never; ; y: number; 


        which it isn't. The notValid type is a number, not a never... so the compiler complains in exactly the place you want.



        Okay, hope that helps. Good luck!







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Mar 26 at 15:49









        jcalzjcalz

        42.1k2 gold badges38 silver badges57 bronze badges




        42.1k2 gold badges38 silver badges57 bronze badges
















            Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.







            Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.



















            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55360087%2ftypescript-extra-keys-in-nested-objects%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

            SQL error code 1064 with creating Laravel foreign keysForeign key constraints: When to use ON UPDATE and ON DELETEDropping column with foreign key Laravel error: General error: 1025 Error on renameLaravel SQL Can't create tableLaravel Migration foreign key errorLaravel php artisan migrate:refresh giving a syntax errorSQLSTATE[42S01]: Base table or view already exists or Base table or view already exists: 1050 Tableerror in migrating laravel file to xampp serverSyntax error or access violation: 1064:syntax to use near 'unsigned not null, modelName varchar(191) not null, title varchar(191) not nLaravel cannot create new table field in mysqlLaravel 5.7:Last migration creates table but is not registered in the migration table

            은진 송씨 목차 역사 본관 분파 인물 조선 왕실과의 인척 관계 집성촌 항렬자 인구 같이 보기 각주 둘러보기 메뉴은진 송씨세종실록 149권, 지리지 충청도 공주목 은진현