Last active
November 8, 2018 15:29
-
-
Save donabrams/b849927f5a0160081db913e3d52cc7b3 to your computer and use it in GitHub Desktop.
Typesafe omit typescript (TS 3.1.6)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This doesn't support map over union types individually | |
type SimpleOmit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>; | |
// The below type, MappedRemoveKey, only works with discrimated unions! | |
// Otherwise the intersection of the types ALSO passes (submiting a TS bug now-- in typescript-3.1.6) | |
// example union type WITHOUT a discriminator | |
type Foo = { foo: string }; | |
type FooBar = { foo: string, bar: string }; | |
type Yay = { yay: true }; | |
type NonDiscriminatedUnion = Foo | FooBar | Yay; | |
// example union type WITH a discriminator | |
type DFoo = { type: 'foo', foo: string }; | |
type DFooBar = { type: 'foobar', foo: string, bar: string }; | |
type DYay = { type: 'yay', yay: true }; | |
type DiscriminatedUnion = DFoo | DFooBar | DYay; | |
type MappedAdd<T, K extends string | number | symbol, V> = T & { [P in K]: V }; | |
type MappedOmit<T, K extends string | number | symbol> = T extends { [P in K]: infer U } | |
? SimpleOmit<T, K> : T; | |
// sanity checks on the NonDiscriminatedUnion type | |
const sanityCheckWorks1: NonDiscriminatedUnion = { foo: 'foo'}; | |
const sanityCheckWorks2: NonDiscriminatedUnion = { foo: 'foo', bar: 'bar'}; | |
const sanityCheckWorks3: NonDiscriminatedUnion = { yay: true}; | |
const sanityCheckFail1: NonDiscriminatedUnion = { }; | |
const sanityCheckFail2: NonDiscriminatedUnion = { foo: 'foo', yay: true }; // FIXME: False positive! | |
const sanityCheckFail3: NonDiscriminatedUnion = { bar: 'bar', yay: true }; // FIXME: False positive! | |
const sanityCheckFail4: NonDiscriminatedUnion = { foo: 'foo', bar: 'bar', yay: true }; // FIXME: False positive! | |
// sanity checks on the Discriminated NonDiscriminatedUnion type | |
const dsanityCheckWorks1: DiscriminatedUnion = { type: 'foo', foo: 'foo' }; | |
const dsanityCheckWorks2: DiscriminatedUnion = { type: 'foobar', foo: 'foo', bar: 'bar' }; | |
const dsanityCheckWorks3: DiscriminatedUnion = { type: 'yay', yay: true }; | |
const dsanityCheckFail1: DiscriminatedUnion = { type: 'foo' }; | |
const dsanityCheckFail2: DiscriminatedUnion = { type: 'foobar' }; | |
const dsanityCheckFail3: DiscriminatedUnion = { type: 'yay' }; | |
const dsanityCheckFail4: DiscriminatedUnion = { type: 'foo', foo: 'foo', bar: 'bar', yay: true }; | |
const dsanityCheckFail5: DiscriminatedUnion = { type: 'foobar', foo: 'foo', bar: 'bar', yay: true }; | |
const dsanityCheckFail6: DiscriminatedUnion = { type: 'yay', foo: 'foo', bar: 'bar', yay: true }; | |
// positive and negative checks on MappedAdd<NonDiscriminatedUnion | |
const addKeyWorks1: MappedAdd<NonDiscriminatedUnion, 'beep', string> = { foo: 'foo', beep: 'beep' }; | |
const addKeyWorks2: MappedAdd<NonDiscriminatedUnion, 'beep', string> = { foo: 'foo', bar: 'bar', beep: 'beep' }; | |
const addKeyWorks3: MappedAdd<NonDiscriminatedUnion, 'beep', string> = { yay: true, beep: 'beep' }; | |
const addKeyWorks4: MappedAdd<NonDiscriminatedUnion, 'foo', string> = { foo: 'foo' }; | |
const addKeyWorks5: MappedAdd<NonDiscriminatedUnion, 'foo', string> = { foo: 'foo', bar: 'bar' }; | |
const addKeyWorks6: MappedAdd<NonDiscriminatedUnion, 'foo', string> = { foo: 'foo', yay: true }; | |
const addKeyFails1: MappedAdd<NonDiscriminatedUnion, 'beep', string> = { foo: 'foo' }; | |
const addKeyFails2: MappedAdd<NonDiscriminatedUnion, 'beep', string> = { foo: 'foo', bar: 'bar' }; | |
const addKeyFails3: MappedAdd<NonDiscriminatedUnion, 'beep', string> = { yay: true }; | |
const addKeyFails4: MappedAdd<NonDiscriminatedUnion, 'foo', string> = { yay: true }; | |
const addKeyFails5: MappedAdd<NonDiscriminatedUnion, 'beep', string> = { foo: 'foo', bar: 'bar', beep: 'beep', yay: true }; // FIXME: False positive! | |
// positive and negative checks on MappedAdd<DiscriminatedUnion | |
const daddKeyWorks1: MappedAdd<DiscriminatedUnion, 'beep', string> = { type: 'foo', foo: 'foo', beep: 'beep' }; | |
const daddKeyWorks2: MappedAdd<DiscriminatedUnion, 'beep', string> = { type: 'foobar', foo: 'foo', bar: 'bar', beep: 'beep' }; | |
const daddKeyWorks3: MappedAdd<DiscriminatedUnion, 'beep', string> = { type: 'yay', yay: true, beep: 'beep' }; | |
const daddKeyWorks4: MappedAdd<DiscriminatedUnion, 'foo', string> = { type: 'foo', foo: 'foo' }; | |
const daddKeyWorks5: MappedAdd<DiscriminatedUnion, 'foo', string> = { type: 'foobar', foo: 'foo', bar: 'bar' }; | |
const daddKeyWorks6: MappedAdd<DiscriminatedUnion, 'foo', string> = { type: 'yay', foo: 'foo', yay: true }; | |
const daddKeyFails1: MappedAdd<DiscriminatedUnion, 'beep', string> = { type: 'foo', foo: 'foo' }; | |
const daddKeyFails2: MappedAdd<DiscriminatedUnion, 'beep', string> = { type: 'foobar', foo: 'foo', bar: 'bar' }; | |
const daddKeyFails3: MappedAdd<DiscriminatedUnion, 'beep', string> = { type: 'yay', yay: true }; | |
const daddKeyFails4: MappedAdd<DiscriminatedUnion, 'foo', string> = { type: 'yay', yay: true }; | |
const daddKeyFails5: MappedAdd<DiscriminatedUnion, 'beep', string> = { type: 'yay', foo: 'foo', bar: 'bar', beep: 'beep', yay: true }; | |
// positive and negative checks on MappedOmit<NonDiscriminatedUnion | |
const removeKeyWorks1: MappedOmit<NonDiscriminatedUnion, 'foo'> = { }; | |
const removeKeyWorks2: MappedOmit<NonDiscriminatedUnion, 'foo'> = { bar: 'bar' }; | |
const removeKeyWorks3: MappedOmit<NonDiscriminatedUnion, 'foo'> = { yay: true }; | |
const removeKeyFails1: MappedOmit<NonDiscriminatedUnion, 'foo'> = { foo: 'foo' }; // FIXME: False positive! | |
const removeKeyFails2: MappedOmit<NonDiscriminatedUnion, 'foo'> = { foo: 'foo', bar: 'bar' }; // FIXME: False positive! | |
// positive and negative checks on MappedOmit<DiscriminatedUnion | |
const dremoveKeyWorks1: MappedOmit<DiscriminatedUnion, 'foo'> = { type: 'foo' }; | |
const dremoveKeyWorks2: MappedOmit<DiscriminatedUnion, 'foo'> = { type: 'foobar', bar: 'bar' }; | |
const dremoveKeyWorks3: MappedOmit<DiscriminatedUnion, 'foo'> = { type: 'yay', yay: true }; | |
const dremoveKeyFails1: MappedOmit<DiscriminatedUnion, 'foo'> = { type: 'foo', foo: 'foo' }; | |
const dremoveKeyFails2: MappedOmit<DiscriminatedUnion, 'foo'> = { type: 'foobar', foo: 'foo', bar: 'bar' }; | |
const dremoveKeyFails3: MappedOmit<DiscriminatedUnion, 'foo'> = { type: 'yay', yay: true, foo: 'foo'}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters
{ | |
"compilerOptions": { | |
"target": "ES2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ | |
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ | |
"strict": true, /* Enable all strict type-checking options. */ | |
"noUnusedParameters": true, /* Report errors on unused parameters. */ | |
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ | |
"noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ | |
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment