Q:

How to flatten the generic types declaration in typescript?

Case:
A function input a nested generic object, and output flat object like follow:
interface Deep<T> {
  p1: T;
  p2: T;
}

type Nested<T> = {
  [P in keyof T]: Deep<any>;
}

type Flat<T, ?> = {
  [P in keyof T]: T[P]?;
}

function flat<T extends Nested<T>>(input: T, p: keyof Deep<any>): Flat<T, ?> {
  const put: any = {}
  for (let k in input)
    put[k] = input[k][p]
}

const foo = flat({
  name: { p1: 'name', p2: 'name' },
  { fn: { p1: () => 0, p2: () => 1 }
})

In this case, the input is a nested object with different Deep type, I hope the typescript could hint me the type of foo.name as a string and the type of foo.fn as () => number.
How should I declare the type of Flat<T, ?>?

A:

I had to fix up your types and code a bit and guess at what you're trying to do, but it looks like this is an example where you wantinference from mapped types.  Instead of trying to describe a type function Flat<> that takes the input Nested<?> and flattens it to produce the output type, do the reverse: think of T as the flattened output type and Nested<T> as the type of the input:
// this is the same
interface Deep<T> {
  p1: T;
  p2: T;
}

// changed: for every property of T with key P and value of type T[P],
// there is a property of Nested<T> with key P and value of type Deep<T[P]>
type Nested<T> = {
  [P in keyof T]: Deep<T[P]>;
}

// output is T, input is Nested<T> and a key of Deep<>
function flat<T>(input: Nested<T>, p: keyof Deep<any>): T {
  const put = {} as T; // assert as type T
  for (let k in input)
    put[k] = input[k][p];
  return put; // added return value
}

And we can use it the way you want:
const foo = flat({
  name: { p1: 'name', p2: 'name' },
  fn: { p1: () => 0, p2: () => 1 },
}, 'p2'); // example code lacked 'p1' or 'p2' argument

foo.name.charAt(0); // works
foo.fn().toFixed(0); // works

Hope that helps; good luck!

