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

// ============ 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?')