Exports Google Chat Takeouts as HTML files
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.
 
chattakeoutreader/typeassert.ts

93 lines
3.5 KiB

import {DateTime, IANAZone} from "luxon";
export type NullableType = "function"|"string"|"object"|"number"|"bigint"|"boolean"|"undefined"|"symbol"|"null"|"array"
export function nullableType(x: unknown): NullableType {
return x === null ? "null" : Array.isArray(x) ? "array" : typeof x
}
export function assertType(x:unknown, expected: "array", context?: string): x is readonly unknown[]
export function assertType(x:unknown, expected: "null", context?: string): x is null
export function assertType(x:unknown, expected: "symbol", context?: string): x is symbol
export function assertType(x:unknown, expected: "undefined", context?: string): x is undefined
export function assertType(x:unknown, expected: "boolean", context?: string): x is boolean
export function assertType(x:unknown, expected: "bigint", context?: string): x is bigint
export function assertType(x:unknown, expected: "number", context?: string): x is number
export function assertType(x:unknown, expected: "object", context?: string): x is object
export function assertType(x:unknown, expected: "string", context?: string): x is string
export function assertType(x:unknown, expected: "function", context?: string): x is Function
export function assertType(x: unknown, expected: NullableType, context?: string):
x is Function|string|object|number|bigint|boolean|undefined|symbol|null|readonly unknown[] {
const actual = nullableType(x)
if (expected !== actual) {
console.log(`expected ${expected}, was ${actual} ${context ? `(in ${context})` : ""}`)
return false
} else {
return true
}
}
export function isObject(x: unknown, context?: string): x is object {
return assertType(x, "object", context)
}
export function isArray(x: unknown, context?: string): x is readonly unknown[] {
return assertType(x, "array", context)
}
export function isString(x: unknown, context?: string): x is string {
return assertType(x, "string", context)
}
export function asString(x: unknown, context?: string): string|null {
if (!isString(x, context)) {
return null
}
return x
}
export function isNumber(x: unknown, context?: string): x is number {
return assertType(x, "number", context)
}
export function asNumber(x: unknown, context?: string): number|null {
if (!isNumber(x, context)) {
return null
}
return x
}
export function isDate(x: unknown, context?: string): x is string {
return asDate(x, context) !== null
}
export function asDate(x: unknown, context?: string): DateTime|null {
if (!isString(x, context)) {
return null
}
const result = DateTime.fromFormat(x, "EEEE', 'MMMM' 'd', 'yyyy' at 'h:mm:ss''a' 'z", {zone: IANAZone.create("UTC"), setZone: true, locale: "en-US"})
if (!result.isValid) {
return null
}
return result
}
export function assertField<T extends string|symbol>(x: object, field: T, context?: string): x is object & {[ key in T ]: unknown} {
if (!(field in x)) {
console.log(`expected ${String(field)} not found${context ? ` (in ${context})` : ""}`)
return false
}
return true
}
export function assertNoExtraFields(x: object, known: Set<string>, context?: string): boolean {
const unknown = Object.keys(x).filter(key => !known.has(key))
if (unknown.length > 1) {
console.log(`unknown fields ${unknown.join(", ")}${context ? ` (in ${context})` : ""}`)
return false
} else if (unknown.length > 0) {
console.log(`unknown field ${unknown[0]}${context ? ` (in ${context})` : ""}`)
return false
}
return true
}