Skip to content

Instantly share code, notes, and snippets.

@rtpg
Last active March 9, 2019 01:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rtpg/30f00608af35489e489be17c4bc9caca to your computer and use it in GitHub Desktop.
Save rtpg/30f00608af35489e489be17c4bc9caca to your computer and use it in GitHub Desktop.
How to write an assertion that two objects are the same shape in Typescript
// this worked in Typescript 3.2.4
// It feels like we should be able to say SameShape<Q extends R, R extends Q>, but this triggers circular reference
// detection in Typescript. Somehow going to {[K in keyof Q]: Q[K]} solves this (though maybe this won't catch things
// like symbols?)
type SameShape<Q extends R, R extends { [K in keyof Q]: Q[K] }> = {
[K in keyof Q]: R[K] // re-asserting every key of Q is present in R with the same type
} & { // anding the types together will catch any conflicts
[K in keyof R]: Q[K] // re-asserting every key of R is present in Q with the same type
}
// unfortunately I didn't see a good way of avoiding repeating the generic type here, but I think there _is_ a way
// to avoid it with infer or ... something. This isn't superb but it gets the job done and should be limited to
// library code
function assertShape<Shape extends { [K in keyof Data]: Data[K] }, Data extends Shape>(
s: Shape,
d: Data
): SameShape<Shape, Data> {
return d as any;
}
assertShape({a: 1, b: 2}, {a: 3, b: 4});
// the following will fail at typecheck
// missing keys
// assertShape(
// {a:1, b:2},
// {a:3, b:4, c:5}
// )
// extra keys
// assertShape(
// {a: 1, b:2},
// {a:1},
// )
// type mismatch
// assertShape({a:1}, {a: 'hi'});
// type mismatch in inner keys
// assertShape({
// a: {a: 3},
// }, {a: {a: 3, b: 4}}
//)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment