//// [isomorphicMappedTypeInference.ts]
type Box<T> = {
    value: T;
}

type Boxified<T> = {
    [P in keyof T]: Box<T[P]>;
}

function box<T>(x: T): Box<T> {
    return { value: x };
}

function unbox<T>(x: Box<T>): T {
    return x.value;
}

function boxify<T>(obj: T): Boxified<T> {
    let result = {} as Boxified<T>;
    for (let k in obj) {
        result[k] = box(obj[k]);
    }
    return result;
}

function unboxify<T>(obj: Boxified<T>): T {
    let result = {} as T;
    for (let k in obj) {
        result[k] = unbox(obj[k]);
    }
    return result;
}

function assignBoxified<T>(obj: Boxified<T>, values: T) {
    for (let k in values) {
        obj[k].value = values[k];
    }
}

function f1() {
    let v = {
        a: 42,
        b: "hello",
        c: true
    };
    let b = boxify(v);
    let x: number = b.a.value;
}

function f2() {
    let b = {
        a: box(42),
        b: box("hello"),
        c: box(true)
    };
    let v = unboxify(b);
    let x: number = v.a;
}

function f3() {
    let b = {
        a: box(42),
        b: box("hello"),
        c: box(true)
    };
    assignBoxified(b, { c: false });
}

function f4() {
    let b = {
        a: box(42),
        b: box("hello"),
        c: box(true)
    };
    b = boxify(unboxify(b));
    b = unboxify(boxify(b));
}

function makeRecord<T, K extends string>(obj: { [P in K]: T }) {
    return obj;
}

function f5(s: string) {
    let b = makeRecord({
        a: box(42),
        b: box("hello"),
        c: box(true)
    });
    let v = unboxify(b);
    let x: string | number | boolean = v.a;
}

function makeDictionary<T>(obj: { [x: string]: T }) {
    return obj;
}

function f6(s: string) {
    let b = makeDictionary({
        a: box(42),
        b: box("hello"),
        c: box(true)
    });
    let v = unboxify(b);
    let x: string | number | boolean = v[s];
}

declare function validate<T>(obj: { [P in keyof T]?: T[P] }): T;
declare function clone<T>(obj: { readonly [P in keyof T]: T[P] }): T;
declare function validateAndClone<T>(obj: { readonly [P in keyof T]?: T[P] }): T;

type Foo = {
    a?: number;
    readonly b: string;
}

function f10(foo: Foo) {
    let x = validate(foo);  // { a: number, readonly b: string }
    let y = clone(foo);  // { a?: number, b: string }
    let z = validateAndClone(foo);  // { a: number, b: string }
}

// Repro from #12606

type Func<T> = (...args: any[]) => T;
type Spec<T> = {
    [P in keyof T]: Func<T[P]> | Spec<T[P]> ;
};

/**
 * Given a spec object recursively mapping properties to functions, creates a function
 * producing an object of the same structure, by mapping each property to the result
 * of calling its associated function with the supplied arguments.
 */
declare function applySpec<T>(obj: Spec<T>): (...args: any[]) => T;

// Infers g1: (...args: any[]) => { sum: number, nested: { mul: string } }
var g1 = applySpec({
    sum: (a: any) => 3,
    nested: {
        mul: (b: any) => "n"
    }
});

// Infers g2: (...args: any[]) => { foo: { bar: { baz: boolean } } }
var g2 = applySpec({ foo: { bar: { baz: (x: any) => true } } });

// Repro from #12633

const foo = <T>(object: T, partial: Partial<T>) => object;
let o = {a: 5, b: 7};
foo(o, {b: 9});
o = foo(o, {b: 9});

// Inferring to { [P in K]: X }, where K extends keyof T, produces same inferences as
// inferring to { [P in keyof T]: X }.

declare function f20<T, K extends keyof T>(obj: Pick<T, K>): T;
declare function f21<T, K extends keyof T>(obj: Pick<T, K>): K;
declare function f22<T, K extends keyof T>(obj: Boxified<Pick<T, K>>): T;
declare function f23<T, U extends keyof T, K extends U>(obj: Pick<T, K>): T;
declare function f24<T, U, K extends keyof T | keyof U>(obj: Pick<T & U, K>): T & U;

let x0 = f20({ foo: 42, bar: "hello" });
let x1 = f21({ foo: 42, bar: "hello" });
let x2 = f22({ foo: { value: 42} , bar: { value: "hello" } });
let x3 = f23({ foo: 42, bar: "hello" });
let x4 = f24({ foo: 42, bar: "hello" });

// Repro from #29765

function getProps<T, K extends keyof T>(obj: T, list: K[]): Pick<T, K> {
    return {} as any;
}

const myAny: any = {};

const o1 = getProps(myAny, ['foo', 'bar']);

const o2: { foo: any; bar: any } = getProps(myAny, ['foo', 'bar']);


//// [isomorphicMappedTypeInference.js]
function box(x) {
    return { value: x };
}
function unbox(x) {
    return x.value;
}
function boxify(obj) {
    var result = {};
    for (var k in obj) {
        result[k] = box(obj[k]);
    }
    return result;
}
function unboxify(obj) {
    var result = {};
    for (var k in obj) {
        result[k] = unbox(obj[k]);
    }
    return result;
}
function assignBoxified(obj, values) {
    for (var k in values) {
        obj[k].value = values[k];
    }
}
function f1() {
    var v = {
        a: 42,
        b: "hello",
        c: true
    };
    var b = boxify(v);
    var x = b.a.value;
}
function f2() {
    var b = {
        a: box(42),
        b: box("hello"),
        c: box(true)
    };
    var v = unboxify(b);
    var x = v.a;
}
function f3() {
    var b = {
        a: box(42),
        b: box("hello"),
        c: box(true)
    };
    assignBoxified(b, { c: false });
}
function f4() {
    var b = {
        a: box(42),
        b: box("hello"),
        c: box(true)
    };
    b = boxify(unboxify(b));
    b = unboxify(boxify(b));
}
function makeRecord(obj) {
    return obj;
}
function f5(s) {
    var b = makeRecord({
        a: box(42),
        b: box("hello"),
        c: box(true)
    });
    var v = unboxify(b);
    var x = v.a;
}
function makeDictionary(obj) {
    return obj;
}
function f6(s) {
    var b = makeDictionary({
        a: box(42),
        b: box("hello"),
        c: box(true)
    });
    var v = unboxify(b);
    var x = v[s];
}
function f10(foo) {
    var x = validate(foo); // { a: number, readonly b: string }
    var y = clone(foo); // { a?: number, b: string }
    var z = validateAndClone(foo); // { a: number, b: string }
}
// Infers g1: (...args: any[]) => { sum: number, nested: { mul: string } }
var g1 = applySpec({
    sum: function (a) { return 3; },
    nested: {
        mul: function (b) { return "n"; }
    }
});
// Infers g2: (...args: any[]) => { foo: { bar: { baz: boolean } } }
var g2 = applySpec({ foo: { bar: { baz: function (x) { return true; } } } });
// Repro from #12633
var foo = function (object, partial) { return object; };
var o = { a: 5, b: 7 };
foo(o, { b: 9 });
o = foo(o, { b: 9 });
var x0 = f20({ foo: 42, bar: "hello" });
var x1 = f21({ foo: 42, bar: "hello" });
var x2 = f22({ foo: { value: 42 }, bar: { value: "hello" } });
var x3 = f23({ foo: 42, bar: "hello" });
var x4 = f24({ foo: 42, bar: "hello" });
// Repro from #29765
function getProps(obj, list) {
    return {};
}
var myAny = {};
var o1 = getProps(myAny, ['foo', 'bar']);
var o2 = getProps(myAny, ['foo', 'bar']);


//// [isomorphicMappedTypeInference.d.ts]
declare type Box<T> = {
    value: T;
};
declare type Boxified<T> = {
    [P in keyof T]: Box<T[P]>;
};
declare function box<T>(x: T): Box<T>;
declare function unbox<T>(x: Box<T>): T;
declare function boxify<T>(obj: T): Boxified<T>;
declare function unboxify<T>(obj: Boxified<T>): T;
declare function assignBoxified<T>(obj: Boxified<T>, values: T): void;
declare function f1(): void;
declare function f2(): void;
declare function f3(): void;
declare function f4(): void;
declare function makeRecord<T, K extends string>(obj: {
    [P in K]: T;
}): { [P in K]: T; };
declare function f5(s: string): void;
declare function makeDictionary<T>(obj: {
    [x: string]: T;
}): {
    [x: string]: T;
};
declare function f6(s: string): void;
declare function validate<T>(obj: {
    [P in keyof T]?: T[P];
}): T;
declare function clone<T>(obj: {
    readonly [P in keyof T]: T[P];
}): T;
declare function validateAndClone<T>(obj: {
    readonly [P in keyof T]?: T[P];
}): T;
declare type Foo = {
    a?: number;
    readonly b: string;
};
declare function f10(foo: Foo): void;
declare type Func<T> = (...args: any[]) => T;
declare type Spec<T> = {
    [P in keyof T]: Func<T[P]> | Spec<T[P]>;
};
/**
 * Given a spec object recursively mapping properties to functions, creates a function
 * producing an object of the same structure, by mapping each property to the result
 * of calling its associated function with the supplied arguments.
 */
declare function applySpec<T>(obj: Spec<T>): (...args: any[]) => T;
declare var g1: (...args: any[]) => {
    sum: number;
    nested: {
        mul: any;
    };
};
declare var g2: (...args: any[]) => {
    foo: {
        bar: any;
    };
};
declare const foo: <T>(object: T, partial: Partial<T>) => T;
declare let o: {
    a: number;
    b: number;
};
declare function f20<T, K extends keyof T>(obj: Pick<T, K>): T;
declare function f21<T, K extends keyof T>(obj: Pick<T, K>): K;
declare function f22<T, K extends keyof T>(obj: Boxified<Pick<T, K>>): T;
declare function f23<T, U extends keyof T, K extends U>(obj: Pick<T, K>): T;
declare function f24<T, U, K extends keyof T | keyof U>(obj: Pick<T & U, K>): T & U;
declare let x0: {
    foo: number;
    bar: string;
};
declare let x1: "foo" | "bar";
declare let x2: {
    foo: number;
    bar: string;
};
declare let x3: {
    foo: number;
    bar: string;
};
declare let x4: {
    foo: number;
    bar: string;
} & {
    foo: number;
    bar: string;
};
declare function getProps<T, K extends keyof T>(obj: T, list: K[]): Pick<T, K>;
declare const myAny: any;
declare const o1: Pick<any, "foo" | "bar">;
declare const o2: {
    foo: any;
    bar: any;
};
