Created
October 7, 2020 12:41
-
-
Save BirgitPohl/ea584183edc083d1efef8ce90f0485e2 to your computer and use it in GitHub Desktop.
A collection of generic types for objects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { testAgainstSchemaDeeply } from "./utils"; | |
interface IMyObject { | |
name: string | |
{[key: string]: any} | |
} | |
class ObjectSchema { | |
name: any | |
} | |
/** | |
* Parses object taking the name property and using it as the key | |
* @param myObject: IMyObject | |
* @fires getDeeplyTypedObject | |
* @returns ObjectSchema | |
*/ | |
const parseObject = (myObject: IMyObject): ObjectSchema => { | |
const prettyObject: any = {}; | |
const {name, ...properties} = myObject; | |
prettyObject[name] = properties; | |
let prettyObjectTyped; | |
try { | |
prettyFontsTyped = getDeeplyTypedObject(prettyObject, new ObjectSchema()); | |
} catch { | |
throw new Error(`Parsing Object didn't work out.`); | |
} | |
return prettyObjectTyped; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Checks if property exists in the target object. | |
* Use for each property | |
* @param object object to check against | |
* @param property property to be checked | |
* @returns boolean, true if it exists | |
*/ | |
export const hasOwnProperty = <T extends {}, P extends PropertyKey>(object: T, property: P): | |
object is NonNullable<T> => { | |
return object.hasOwnProperty(property); | |
}; | |
export const isInstanceOf = <S, T extends FunctionConstructor>(source: S, target: T): T => { | |
if (source instanceof target) { | |
return source as unknown as T | |
} else { | |
throw new Error(`Object doesn't match the schema.`); | |
} | |
}; | |
type ObjectDescriptor<D> = { | |
data?: D; | |
}; | |
export function makeTypedObject<D>(desc: ObjectDescriptor<D>): D { | |
let data: object = desc.data || {}; | |
return { ...data } as D; | |
} | |
/** | |
* Checks if property exists in the target object. | |
* @Description Since we check type on Javascript level, we can safely cast type as T | |
* @param source any object | |
* @param schema any class | |
* @returns boolean | Error | |
*/ | |
export const testAgainstSchema = <S extends {[key: string]: string},T extends {[key: string]: string}> | |
(source: S, schema: T): boolean | Error => { | |
const keysOfSource = Object.keys(source); | |
const keyOfSchema = Object.keys(schema); | |
for (const key of keysOfSource) { | |
if (!schema.hasOwnProperty(key)) { | |
throw new Error(`Property ${key} doesn't exist.`); | |
} | |
} | |
for (const key of keyOfSchema) { | |
if (!source.hasOwnProperty(key)) { | |
throw new Error(`Property ${key} is missing.`); | |
} | |
} | |
return true; | |
}; | |
/** | |
* Checks deeply a source object against a schema. | |
* @Description We type-check in Javascript-level | |
* @param source any object | |
* @param schema any class | |
* @returns boolean | Error | |
*/ | |
export const testAgainstSchemaDeeply = <X extends {[key: string]: any}, Y extends {[key: string]: any}> | |
(source: X, schema: Y): boolean | Error => { | |
const keysOfSource: string[] = Object.keys(source); | |
const keysOfSchema: string[] = Object.keys(schema); | |
// test if a key is to much | |
for (const key of keysOfSource) { | |
if (!hasOwnProperty(schema, key)) { | |
throw new Error(`Property ${key} in object to be tested doesn't exist in the schema.`); | |
} | |
// 👀 It's a tree! | |
if (typeof source[key] === "object" && typeof schema[key] == "object") { | |
getDeeplyTypedObject(source[key], schema[key]); | |
} | |
} | |
for (const key of keysOfSchema) { | |
if (!hasOwnProperty(source, key)) { | |
throw new Error(`Property ${key} is missing in object to be tested.`); | |
} | |
// 👀 It's a tree! | |
if (typeof schema[key] === "object" && typeof source[key] == "object") { | |
getDeeplyTypedObject(schema[key], source[key]); | |
} | |
} | |
return true; | |
} | |
/** | |
* Checks if property exists in the target object. | |
* @Description Since we check type on Javascript level, we can safely cast type as T | |
* @param sourceObject any object | |
* @param TargetType any class | |
* @returns sourceObject as T | |
*/ | |
export const getTypedObject = <S extends {},T extends {}>(sourceObject: S, targetType: T): T => { | |
const keysOfSource = Object.keys(sourceObject); | |
const keyOfTarget = Object.keys(targetType); | |
for (const key of keysOfSource) { | |
if (!targetType.hasOwnProperty(key)) { | |
throw new Error(`Property ${key} doesn't exist.`); | |
} | |
} | |
for (const key of keyOfTarget) { | |
if (!sourceObject.hasOwnProperty(key)) { | |
throw new Error(`Property ${key} is missing.`); | |
} | |
} | |
return sourceObject as unknown as T; | |
}; | |
/** | |
* Checks deeply if property exists in the target object. | |
* @Description Since we check type on Javascript level, we can safely cast type as T | |
* @param sourceObject any object | |
* @param TargetType any class | |
* @returns sourceObject as T | Error | |
*/ | |
export const getDeeplyTypedObject = <S extends {[key: string]: any}, T extends {[key: string]: any;}> | |
(sourceObject: S, targetType: T): T => { | |
const keysOfSource: string[] = Object.keys(sourceObject); | |
const keyOfTarget: string[] = Object.keys(targetType); | |
for (const key of keysOfSource) { | |
if (!hasOwnProperty(targetType, key)) { | |
throw new Error(`Property ${key} doesn't exist`); | |
} | |
// 👀 It's a tree! | |
if (typeof sourceObject[key] === "object" && typeof targetType[key] == "object") { | |
getDeeplyTypedObject(sourceObject[key], targetType[key]); | |
} | |
} | |
for (const key of keyOfTarget) { | |
if (!hasOwnProperty(sourceObject, key)) { | |
throw new Error(`Property ${key} doesn't exist`); | |
} | |
// 👀 It's a tree! | |
if (typeof targetType[key] === "object" && typeof sourceObject[key] == "object") { | |
getDeeplyTypedObject(targetType[key], sourceObject[key]); | |
} | |
} | |
return sourceObject as unknown as T; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment