TypeScript type ignore case

后端 未结 4 1215
悲哀的现实
悲哀的现实 2021-02-12 22:42

I have this type definition in TypeScript:

export type xhrTypes = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"OPTIONS\" | \"CONNECT\" | \"HEAD\";
4条回答
  •  时光说笑
    2021-02-12 23:11

    While not the types that were asked for, if an enum would be okay then the following can be used for case-insensitive matching of enum string values:

    /**
     * Gets an enumeration given a case-insensitive key. For a numeric enum this uses
     * its members' names; for a string enum this searches the specific string values.
     * Logs a warning if the letter case was ignored to find a match, and logs an error
     * including the supported values if no match was found.
     */
    static toEnumIgnoreCase(target: T, caseInsentiveKey: string): T[keyof T] {
        const needle = caseInsentiveKey.toLowerCase();
    
        // If the enum Object does not have a key "0", then assume a string enum
        const key = Object.keys(target)
          .find(k => (target['0'] ? k : target[k]).toLowerCase() === needle);
    
        if (!key) {
            const expected = Object.keys(target)
              .map(k => target['0'] ? k : target[k])
              .filter(k => isNaN(Number.parseInt(k)))
              .join(', ');
            console.error(`Could not map '${caseInsentiveKey}' to values ${expected}`);
            return undefined;
        }
    
        const name = target['0'] ? key : target[key];
        if (name !== caseInsentiveKey) {
            console.warn(`Ignored case to map ${caseInsentiveKey} to value ${name}`);
        }
    
        return target[key];
    }
    

    Of course, as this loops over possible values, it's really only meant to handle things like configuration files; all code should really use the enum values instead.

    Some tests:

    import Spy = jasmine.Spy;
    import {ConfigHelper} from './config-helper';
    
    // Should match on One, one, ONE and all:
    enum NumberEnum { One, Two, Three }
    
    // Should match on Uno, uno, UNO and all, but NOT on One, one, ONE and all:
    enum StringEnum { One = 'Uno', Two = 'Dos', Three = 'Tres' }
    
    describe('toEnumIgnoreCase', () => {
    
        beforeEach(function () {
            spyOn(console, 'warn');
            spyOn(console, 'error');
        });
    
        it('should find exact match for numeric enum', () => {
            const result = ConfigHelper.toEnumIgnoreCase(NumberEnum, 'One');
            expect(result).toBe(NumberEnum.One);
            expect(console.warn).not.toHaveBeenCalled();
            expect(console.error).not.toHaveBeenCalled();
        });
        it('should find case-insensitive match for numeric enum', () => {
            const result = ConfigHelper.toEnumIgnoreCase(NumberEnum, 'two');
            expect(result).toBe(NumberEnum.Two);
            expect(console.warn).toHaveBeenCalled();
            expect((console.warn as Spy).calls.mostRecent().args[0])
              .toMatch(/value Two/);
            expect(console.error).not.toHaveBeenCalled();
        });
        it('should yield undefined for non-match for numeric enum', () => {
            const result = ConfigHelper.toEnumIgnoreCase(NumberEnum, 'none');
            expect(result).toBe(undefined);
            expect(console.warn).not.toHaveBeenCalled();
            expect(console.error).toHaveBeenCalled();
            expect((console.error as Spy).calls.mostRecent().args[0])
              .toMatch(/values One, Two, Three/);
        });
    
        it('should find exact match for string enum', () => {
            const result = ConfigHelper.toEnumIgnoreCase(StringEnum, 'Uno');
            expect(result).toBe(StringEnum.One);
            expect(console.warn).not.toHaveBeenCalled();
            expect(console.error).not.toHaveBeenCalled();
        });
        it('should find case-insensitive match for string enum', () => {
            const result = ConfigHelper.toEnumIgnoreCase(StringEnum, 'dos');
            expect(result).toBe(StringEnum.Two);
            expect(console.warn).toHaveBeenCalled();
            expect((console.warn as Spy).calls.mostRecent().args[0])
              .toMatch(/value Dos/);
            expect(console.error).not.toHaveBeenCalled();
        });
        it('should yield undefined for name rather than string value', () => {
            const result = ConfigHelper.toEnumIgnoreCase(StringEnum, 'One');
            expect(result).toBe(undefined);
            expect(console.warn).not.toHaveBeenCalled();
            expect(console.error).toHaveBeenCalled();
            expect((console.error as Spy).calls.mostRecent().args[0])
              .toMatch(/values Uno, Dos, Tres/);
        });
        it('should yield undefined for non-match for string enum', () => {
            const result = ConfigHelper.toEnumIgnoreCase(StringEnum, 'none');
            expect(result).toBe(undefined);
            expect(console.warn).not.toHaveBeenCalled();
            expect(console.error).toHaveBeenCalled();
            expect((console.error as Spy).calls.mostRecent().args[0])
              .toMatch(/values Uno, Dos, Tres/);
        });
    });
    

提交回复
热议问题