Skip to content

Instantly share code, notes, and snippets.

@hraban
Last active March 24, 2017 03:19
Show Gist options
  • Save hraban/66c1778cdd31868034b12db93fcce41c to your computer and use it in GitHub Desktop.
Save hraban/66c1778cdd31868034b12db93fcce41c to your computer and use it in GitHub Desktop.
Checked subset typing in TypeScript
// Imagine you want to explicitly define which members of a public API
// interface your implementation actually uses. Example: you implement
// a web extension, but only use a few of the members on the argument
// to the onHeadersReceived handler. Explicitly typing this is useful
// when creating mocks in your unit tests.
//
// Here's now you could do it:
// Inverse keyword of "extends": ensure every member of type Sub exists
// on type Super.
function EnsureSubsetType<Sub, Super extends Sub>() {}
// Explicit list of fields we use from the webrequest API.
interface ResponseDetails {
url: string;
requestId: string;
tabId: number;
responseHeaders?: chrome.webRequest.HttpHeader[];
}
EnsureSubsetType<ResponseDetails, chrome.webRequest.WebResponseDetails>(); // this does actual checking
export class MyPlugin {
// ...
onHeadersReceived(details: ResponseDetails) {
// use only the fields on details which you defined above
}
// ...
}
// Try adding a random field in the struct above and see the type
// checking line fail.
//
// This makes unit testing MyPlugin easier. Without it, if I call the
// onHeadersReceived method in my unit test, I'm not sure which fields
// I _actually_ need to mock. Now the typechecker tells me. Without it,
// I'd be mocking all kinds of unnecessary detailed fields which my
// plugin doesn't actually need.
//
// Limitation: this does not work for optional members! the responseHeaders field
// above could be called anything or have any type and it would pass the typecheck.
@codeandcats
Copy link

Neat trick 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment