Yup: Add TypeScript types

Created on 16 May 2017  路  18Comments  路  Source: jquense/yup

Most helpful comment

Instead of having the types maintained separately, is there any hope of converting the main repo here to TS instead of JS, so types are mainated automatically along with updates?

All 18 comments

I don't use typescript very often so i'd be hard to keep any type defs up to date, but I'd be open to a PR adding them.

I made an attempt to add types but gave up after about 30 min. Would be good to find another builder pattern library鈥檚 type def for reference

Yeah I was wondering if joi had decent types TS, or flow. I might check

Here's what I made so far, its gets the job done for me

declare var yup: yup.Yup;

declare module 'yup' {
    export = yup;
}

declare namespace yup {

    interface Yup {
        reach<T extends YupBase<T>>(schema: T, path: string, value?: object, context?: object): T;
        addMethod<T extends YupBase<T>>(schemaType: T, name: string, method: () => T): void;
        ref(path: string, options: { contextPrefix: string }): Ref;
        lazy<T extends YupBase<T>>(fn: (value: any) => T): Lazy;
        ValidationError(errors: string | Array<string>, value: any, path: string);
        mixed(): YupMixed;
        string(): YupString;
        object(): YupObject;
    }

    interface YupMixed extends YupBase<YupMixed>{

    }


    interface YupBase<T extends YupBase<T>>{
        clone(): T;
        label(label: string): T;
        meta(metadata: object): T;
        describe(): SchemaDescription;
        concat(schema: T);
        validate<U>(value: U, options?: object): Promise<ValidationError|U>;
        validate<U>(value: U, options?: object, callback?: (value?: U, error?: ValidationError ) => any): void;
        isValid(value: any, options?: object, callback?: () => any): Promise<boolean>;
        cast(value: any): any;
        isType(value: any): boolean;
        strict(isStrict?: boolean): T;
        strip(stripField?: boolean): T;
        withMutation(builder: (current: T) => void): void;
        default(value: any): T;
        default(): Any;
        nullable(isNullable?: boolean): T;
        required(message?: string): T;
        typeError(message: string): T;
        oneOf(arrayOfValues: Array<any>, message?: string): T;
        notOneOf(arrayOfValues: Array<any>, message?: string);
        when(keys: string | Array<string>, builder: object |
            ((value, schema: T) => T) |
            ((v1, v2, schema: T) => T) |
            ((v1, v2, v3, schema: T) => T)|
            ((v1, v2, v3, v4, schema: T) => T)): T;
        test(name: string, message: string, test: () => any, callbackStyleAsync?: boolean): T;
        test(options: object): T;
        transform(fn: (currentValue: any, originalValue: any) => any): T;
    }

    interface YupString extends YupBase<YupString> {
        required(message?: string): YupString;
        min(limit: number | Ref, message?: string): YupString;
        max(limit: number | Ref, message?: string): YupString;
        matches(regex: RegExp, message?: string): YupString;
        email(message?: string): YupString;
        url(message?: string): YupString;
        ensure(): YupString;
        trim(message?: string): YupString;
        lowercase(message: string): YupString;
        uppercase(message: string): YupString;
    }

    interface YupObject extends YupBase<YupObject> {
        shape(fields: object, noSortEdges?: Array<[string, string]>): YupObject;
        from(fromKey: string, toKey: string, alias: boolean): YupObject;
        noUnknown(onlyKnownKeys: boolean, message?: string): YupObject;
        camelCase(): YupObject;
        constantCase(): YupObject;
    }

    interface SchemaDescription {

    }

    interface Ref {

    }

    interface Lazy {

    }

    interface ValidationError {
        path: string;
        value: any;
        type: any;
        errors: Array<string>;
        inner: Array<ValidationError>;

    }

    interface Any {

    }

}

This is what I came up with:

declare const yup: Yup;

declare module "yup" {
    export = yup;
}

interface Yup {
    reach(schema: Schema, path: string, value?: any, context?: any): Schema;

    addMethod(schemaType: Schema, name: string, method: () => Schema): void;

    ref(path: string, options: { contextPrefix: string }): Ref;

    lazy(fn: (value: any) => Schema): Lazy;

    mixed(): Schema;

    string(): StringSchema;

    number(): NumberSchema;

    boolean(): BooleanSchema;

    date(): DateSchema;

    array(): ArraySchema;

    object(): ObjectSchema;
}

interface ValidationError {
    errors: string | Array<string>;

    value: any;

    path: string;

    inner?: Array<ValidationError>;
}

interface Ref {

}

interface Lazy {

}

interface Schema {
    clone(): Schema;

    label(label: string): Schema;

    meta(metadata: any): Schema;

    describe(): SchemaDescription;

    concat(schema: Schema): Schema;

    validate(value: any, options?: ValidateOptions, callback?: () => void): Promise<any>;

    isValid(value: any, options?: any, callback?: () => void): Promise<any>;

    cast(value: any): any;

    isType(value: any): boolean;

    strict(isStrict: boolean): Schema;

    strip(stripField: boolean): Schema;

    withMutation(builder: (current: Schema) => void): void;

    default(value: any): Schema;

    default(): any;

    nullable(isNullable: boolean): Schema;

    required(message?: string): Schema;

    typeError(message?: string): Schema;

    oneOf(arrayOfValues: Array<any>, message?: string): Schema;

    equals(arrayOfValues: Array<any>, message?: string): Schema;

    notOneOf(arrayOfValues: Array<any>, message?: string): Schema;

    when(keys: string | Array<string>, builder: any | ((value: any, schema: Schema) => Schema)): Schema;

    test(name: string, message: string, test: Function, callbackStyleAsync?: boolean): Schema;

    test(options: any): Schema;

    transform(transformation: (currentValue: any, originalValue: any) => any): Schema;
}

interface StringSchema extends Schema {
    required(message?: string): StringSchema;

    min(limit: number | Ref, message?: string): StringSchema;

    max(limit: number | Ref, message?: string): StringSchema;

    matches(regex: RegExp, message?: string): StringSchema;

    email(message?: string): StringSchema;

    url(message?: string): StringSchema;

    ensure(): StringSchema;

    trim(message?: string): StringSchema;

    lowercase(message?: string): StringSchema;

    uppercase(message?: string): StringSchema;
}

interface NumberSchema extends Schema {
    min(limit: number | Ref, message?: string): NumberSchema;

    max(limit: number | Ref, message?: string): NumberSchema;

    positive(message?: string): NumberSchema;

    negative(message?: string): NumberSchema;

    integer(message?: string): NumberSchema;

    truncate(): NumberSchema;

    round(type: "floor" | "ceil" | "trunc" | "round"): NumberSchema;
}

interface BooleanSchema extends Schema {

}

interface DateSchema extends Schema {
    min(limit: Date | string | Ref, message?: string): DateSchema;

    max(limit: Date | string | Ref, message?: string): DateSchema;
}

interface ArraySchema extends Schema {
    of(type: Schema): ArraySchema;

    required(message?: string): ArraySchema;

    min(limit: number | Ref, message?: string): ArraySchema;

    max(limit: number | Ref, message?: string): ArraySchema;

    ensure(): ArraySchema;

    compact(rejector: (value: any) => boolean): ArraySchema;
}

interface ObjectSchema extends Schema {
    shape(fields: any, noSortEdges?: Array<[string, string]>): ObjectSchema;

    from(fromKey: string, toKey: string, alias: boolean): ObjectSchema;

    noUnknown(onlyKnownKeys: boolean, message?: string): ObjectSchema;

    camelCase(): ObjectSchema;

    constantCase(): ObjectSchema;
}

interface ValidateOptions {

}

interface SchemaDescription {
    type: string;
    label: string;
    meta: object;
    tests: Array<string>;
}

It should cover all available API features.

I would suggest to bundle the typings with yup, see http://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html

It looks good, why not publish to DefinitelyTyped?

Pull request #21857 Type definitions for Yup submitted to DefinitelyTyped

Pull Request to Add Type Definitions was merged.
You can get them here https://www.npmjs.com/package/@types/yup

npm install --save-dev @types/yup

Thanks to @vtserman for the typings! On the other hand, there are arguments to keep the typings and the project together. Whether they are separated, i.e. on DefinitelyTyped, or together, updates are always needed.

Is there any way to resolve Ref values using Yup in TypeScript? I can`t see resolve method in any provided TypeScript interface and it was useful in some cases like https://github.com/jquense/yup/issues/49 (for example if we want to provide synchronous validation of two connected mixed fields in scheme).

Just for the record, would love to see the typings officially maintained. Maybe not so difficult if the public surface area of this package is nice and stable. TS adoption doing quite well these days!

any update here?

Typings can be found in the DefinitelyTyped repo

I would add they are a bit wrong but generally good 馃憤

When I want to concat two objects with different values it throws a type error. Can someone help fixing the types?

Not working but should work:

const one = yup.object().shape({
  one: yup.string(),
});

const two = yup.object().shape({
  two: yup.string(),
});

export const oneAndTwo = one.concat(
  two,
);
const two: yup.ObjectSchema<yup.Shape<{}, {
    two: string;
}>>
Argument of type 'ObjectSchema<Shape<{}, { two: string; }>>' is not assignable to parameter of type 'ObjectSchema<Shape<{}, { one: string; }>>'.
  Type 'Shape<{}, { two: string; }>' is not assignable to type 'Shape<{}, { one: string; }>'.
    Property 'one' is missing in type 'Shape<{}, { two: string; }>' but required in type '{ one: string; }'.ts(2345)

Another problem is that the returned type is wrong.

const oneAndTwo: yup.ObjectSchema<yup.Shape<{}, {
    one: string;
}>>

No type error:

const one = yup.object().shape({
  one: yup.string(),
});

const two = yup.object().shape({
  one: yup.string(),
});

export const oneAndTwo = one.concat(
  two,
);

or

const one = yup.object().shape({
  one: yup.string(),
});

const two = yup.object().shape({
  one: yup.string(),
  two: yup.string(),
});

export const oneAndTwo = one.concat(
  two,
);

How can i use Union Types ?

const catSchema =  yup.object().shape({cat: yup.string() })
const dogSchema =  yup.object().shape({dog: yup.number() })

type Cat = yup.InferType<typeof catSchema>
type Dog = yup.InferType<typeof dogSchema>
type animal = Cat | Dog

Instead of having the types maintained separately, is there any hope of converting the main repo here to TS instead of JS, so types are mainated automatically along with updates?

Was this page helpful?
0 / 5 - 0 ratings