neuronet
neuronet

Reputation: 1159

How to write a type for a method that returns a value from an array of keys, where the data are nested objects with primitive values and classes

How to write type for getIn method (GetInResult)? I want the result to point to the string type from the Second.second interface of the e2 Example class.

type DataValue = undefined | null | boolean | string | number | bigint |  Example<any>;

// DataType can be object or array with primitive values or Example instances
interface DataType {
    [key: PropertyKey]: DataValue;
}


type Keys = readonly PropertyKey[];
type GetInResult<T, KS extends Keys> = KS extends [infer F, ...infer R]
  ? F extends keyof T
    ? R extends Keys
      ? T[F] extends Example<infer NestedT>
        ? NestedT extends DataType 
          ? GetInResult<NestedT, R> 
          : undefined
        : T[F]
      : T[F]
    : undefined
  : undefined;

class Example<T extends DataType> {
    #data: T;
    constructor(data: T){
        this.#data = data;
    }

    getIn<KS extends Keys, K extends PropertyKey>(keys: KS & K[]): GetInResult<T, KS> {
    const key = keys.shift();
    if (key && Object.prototype.hasOwnProperty.call(this.#data,key)) {
      const value = this.#data[key];
      if (keys.length) {
        if (value instanceof Example) {
          return value.getIn(keys);
        }
        return undefined;
      }
      return value; // error: check playground below
    }
    return undefined;
  }
}

interface Second extends DataType {
    second: string;
}

const second: Second = {
    second: '2'
}

const e2 = new Example(second);


interface First extends DataType {
    first: string;
    firstNested: Example<Second>;
}


const first: First = {
    first:'1',
    firstNested: e2
};

const e1 = new Example(first);

const result = e1.getIn(['firstNested','second']);
// result should be a string from Second.second interface because firstNested is pointing to the Example<Second> and second points to Second.second

Playground

Upvotes: 0

Views: 168

Answers (2)

neuronet
neuronet

Reputation: 1159

I made modifications to @myNameIsDu's code and was able to achieve a satisfactory result.

playground

Upvotes: 1

myNameIsDu
myNameIsDu

Reputation: 73

Maybe you need this

The difference is that data is not private and requires const assertions

Upvotes: 1

Related Questions