| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 | interface Props {
  name: string
}
interface Core {
  id: string
}
interface Instance extends Props, Core {}
const defaults: Props = {
  name: "Spot",
}
const core: Core = {
  id: "0",
}
class ClassInstance<T extends object = {}> implements Instance {
  id = "0"
  name = "Spot"
  constructor(
    props: Partial<Props> &
      { [K in keyof T]: K extends keyof Core ? never : T[K] }
  ) {
    Object.assign(this, props)
  }
}
interface InstanceConstructor {
  new <T extends object = {}>(
    props: Partial<Props> &
      { [K in keyof T]: K extends keyof Core ? never : T[K] }
  ): Instance
}
function makeInstance<T extends object = {}>(
  props: Partial<Props> &
    { [K in keyof T]: K extends keyof Core ? never : T[K] } &
    ThisType<ClassInstance>
) {
  return new ClassInstance<T>({ ...defaults, ...props, ...core })
}
function getInstance<T extends object = {}>(
  props: Partial<Props> &
    { [K in keyof T]: K extends keyof Core ? never : T[K] }
) {
  return { ...defaults, ...props, ...core }
}
const instance = getInstance({
  name: "Steve",
  age: 93,
  wag(this: Instance) {
    return this.name
  },
})
interface AnimalProps {
  name: string
  greet(this: Animal, name: string): string
}
interface AnimalCore {
  id: string
  sleep(this: Animal): void
}
interface Animal extends AnimalProps, AnimalCore {}
const getAnimal = <T extends object>(
  props: Partial<AnimalProps> &
    { [K in keyof T]: K extends keyof AnimalCore ? never : T[K] }
): Animal & T => {
  return {
    // Defaults
    name: "Animal",
    greet(name) {
      return "Hey " + name
    },
    // Overrides
    ...props,
    // Core
    id: "hi",
    sleep() {},
  }
}
const dog = getAnimal({
  name: "doggo",
  greet(name) {
    return "Woof " + this.name
  },
  wag() {
    return "wagging..."
  },
})
dog.greet("steve")
dog.wag()
dog.sleep()
class ShapeTest {}
const shapeTest = new ShapeTest()
export default shapeTest
type Greet = (name: string) => string
const greet: Greet = (name: string | number) => {
  return "hello " + name
}
 |