generated from garrettmills/template-npm-typescript
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
64 lines
2.5 KiB
64 lines
2.5 KiB
|
|
// ============ An example using dependent types to overload function signatures ============
|
|
// In this example, we define a type CertCheckResponse which defines the structure of a response
|
|
// object for a hypothetical certificate validation API.
|
|
// We then implement a function sendCheckResponse whose return type and parameter signature
|
|
// depends on the value of the success parameter.
|
|
|
|
/** A helper function that gets a Date one hour in the future. */
|
|
function inOneHour(): Date {
|
|
const d = new Date()
|
|
d.setMinutes(d.getMinutes() + 60)
|
|
return d
|
|
}
|
|
|
|
|
|
/** A type conditional on a boolean parameter. */
|
|
type CertCheckResponse<Success extends boolean> = Success extends true
|
|
? {issuer: string, expires: Date}
|
|
: {error: string}
|
|
|
|
|
|
// Hover over the identifier to view the computed types.
|
|
type ExampleSuccess = CertCheckResponse<true>
|
|
type ExampleFail = CertCheckResponse<false>
|
|
|
|
|
|
/**
|
|
* This is where the magic happens. We combine TypeScripts function/method overloading with
|
|
* the dependent types to make not only the return type but also the function signature dependent
|
|
* on the value of the `success` parameter.
|
|
*
|
|
* (The third and final signature is the signature of the underlying implementation and must be
|
|
* compatible with all the other signatures.)
|
|
*
|
|
* @param success
|
|
* @param issuer
|
|
* @param expires
|
|
*/
|
|
function sendCheckResponse(success: true, issuer: string, expires: Date): CertCheckResponse<typeof success>
|
|
function sendCheckResponse(success: false, error: string): CertCheckResponse<typeof success>
|
|
function sendCheckResponse(success: boolean, issuerOrError: string, expires?: Date): CertCheckResponse<typeof success>
|
|
function sendCheckResponse(success: boolean, issuerOrError: string, expires: Date = new Date()): CertCheckResponse<typeof success> {
|
|
if ( success ) {
|
|
return {
|
|
issuer: issuerOrError,
|
|
expires: expires,
|
|
}
|
|
}
|
|
|
|
return {error: issuerOrError}
|
|
}
|
|
|
|
|
|
const successResponse = sendCheckResponse(true, 'contoso.com', inOneHour()) // => {issuer: string, expires: Date}
|
|
const failureResponse = sendCheckResponse(false, 'Invalid issuer.') // => {error: string}
|
|
|
|
// Interestingly, this gracefully degrades to more general types when the value
|
|
// of success cannot be inferred statically. This is why we include the 3rd overload
|
|
// signature with `success: boolean`.
|
|
let someBool!: boolean // example of a non-specific boolean value
|
|
|
|
// This has the union type {issuer: string, expires: Date} | {error: string}
|
|
const ambiguousResponse = sendCheckResponse(someBool, 'String?')
|