더 좋은 타자 스크립트...JavaScript 사용

[주의: 본고에서 인용한 라이브러리-allow-현재 NPM 패키지에서 찾을 수 있습니다. 여기서 찾을 수 있습니다: https://www.npmjs.com/package/@toolz/allow]
이전 게시물 () 에서 TypeScript가 왜 나에게 큰 실패인지 설명했습니다.많은 추가 업무가 거짓된 안정감과 적은 실제 이익으로 바뀌었다.
나는 다시는 그런 논점을 반복하지 않을 것이다.만약 네가 흥미가 있다면, 그 문장을 훑어볼 수 있다.본고에서 저는 순수한 JavaScript 환경에서의 실용적이고 전술적인 해결 방안을 개술하고자 합니다.
FWIW, 나는 3월에 비슷한 글을 썼다 ().비록 나의 방법의 기초는 근본적으로 바뀌지 않았지만, 나의 실현의 구체적인 상황은 크게 다르다.
이 문서의 모든 코드는 이 파일에서 참조할 수 있습니다.
https://github.com/bytebodger/spotify/blob/master/src/classes/allow.js
이것은 나의 Spotify Toolz 프로젝트의 일부분이지만, 나는 그것을 나의 유형 검사 라이브러리에 이식할 것이다.

유형 검사 대상


내 이전 글의 내용을 다시 기술하지 않는 상황에서 나는 유형 검사에서 몇 가지 관건적인 요소가 매우 중요하다는 것을 발견했다고 말하고 싶다.
  • 나는 거의 운행할 때의 유형 안전을 확보하는 데만 관심을 갖는다.나에게 너의 응용 프로그램 컴파일은 나에게 거의 의미가 없다고 말해라.응용 프로그램이 컴파일되었습니다.나는 신발끈을 묶는다.우리는 차를 몰고 절벽을 내려가지 않았다.우리 다 과자 있어??만약 나의 응용 프로그램이 컴파일될 수 있다면, 그것도 실행될 수 있을 것이라고 보장할 수 없다.만약 나의 응용 프로그램이 실행된다면, 컴파일할 수 있을 것이다.그래서 내가 주목하는 건 운행할 때야.
  • 나는 거의 응용 프로그램 간의 인터페이스 유형의 안전을 확보하는 데만 관심을 갖는다.이것들은 아마도 나의 응용 프로그램과 일부 외부 데이터 원본(예를 들어 API) 사이의 인터페이스일 것이다.또는 그것은 하나의 함수와 다른 함수 사이의 인터페이스가 될 수 있다.교환이 내 응용 프로그램 밖에 도착했는지, 아니면 교환이 완전히 응용 프로그램에 의해 봉인되었는지는 중요하지 않다.관건은 만약 내가 얻은 것이'깨끗한'입력이라는 것을 안다면, 내가 응용 프로그램에서 작성한 어떤 논리도 예상대로 실행될 수 있다는 것이다.
  • 유형 검사는 청결해야 한다.스피드능률적만약 내가 컴파일러에게 기능 코드를 설명하는 데 무수한 시간을 들여야 한다면, 유형 검사는 하나의 기능이라기보다는 장애물이다.이것 또한 유형 검사가 더 많은 것이 아니라 가능한 한 완성되어야 한다는 것을 의미한다.다시 말하면 100개의 키를 포함하는 API 응답에서 대상을 받았지만 그 중 3개의 키만 사용했다면 다른 97개의 키를 정의할 필요가 없다.
  • '방어적 프로그래밍'은 최소한으로 유지해야 한다.이전 게시물에서 나는 if개의 연속 검사 흐름을 사용하여 우리가 정확한 데이터를 받았는지 확인해야 한다는 골치 아픈 문제를 잘 지적했다.나는 이 점을 완전히 이해한다.새로운 if 수표를 계속 써야 하는 모든 해결 방안은 비해결 방안이다.

  • 기본 방법


    지난번 글에서 나는 한 장면을 개술했다. 우리는 number을 전송할 수 있지만, 매개 변수가 number인지 확인하기 위해 함수 내부를 검사해야 한다.장면은 다음과 같습니다.
    const createId = (length = 32) => {
      if (isNaN(length)) length = 32;
      // rest of function...
    }
    
    간단한 사실은 우리가 운행할 때의 문제를 겨냥하기만 하면 정말 이 문제를 해결할 방법이 없다는 것이다.이것이 바로 나의 거의 모든 검증이 실행할 때 검증에 집중되는 이유이다.나는 성공적인 번역이 가져오는 허위 안전성에 흥미가 없기 때문이다.

    I want to know, in real-time, whether something will fail at runtime.


    따라서 이 문제에 대한 나의 답은 만약에 내가 함수체 내부의 검증을 없애지 못한다면 적어도 그것들을 깨끗하고 신속하며 효율적으로 하고 싶다는 것이다.손으로 정교하게 만들 필요가 없는 if 조건.
    위에서 링크된 코드에서 저는 기본적인 검증 클래스를 가지고 있습니다. 저는 allow이라고 합니다.allow은 각종 데이터 유형을 검사하는 일련의 방법을 포함한다.
    나의 새로운 방법의 관건적인 차이점은 모든 방법이 연결되어 있다는 것이다.이것은 내가 한 줄의 코드로 모든 검증을 실행할 수 있다는 것을 의미한다.따라서 함수에 매개 변수가 있든 없든 함수 내부에 이 입력을 검증하는 데 사용되는 대량의 LoC가 없습니다.
    또 다른 차이점은 나의 최신 방법은 어떠한 검증 값도 되돌려 주지 않는다는 것이다.이 방법은 간단하게 throw에서 틀리거나...아무 일도 없었어요.이것이 바로 내가 원하는 것이다.
    물론 생산 과정에서'실패'가 어떤 소리 없는 오류를 초래할 수 있도록 코드를 조정할 수 있다.그러나 관건은 함수가'나쁜'데이터를 수신한다면 나는 이 함수가 어떤 방식으로 퇴출되기를 바란다.
    따라서 다음 예는 이와 유사하게 보입니다.
    const myFunction = (someBoolean = false, someString = '') => {
      allow.aBoolean(someBoolean).aString(someString);
      // rest of function...
    }
    
     

    가장 간단한 검증


    나는 값을 전달하고 유효한지 확인하는 것 외에 할 일이 없기 때문에 간단하다고 부른다.그것들은 이렇게 보인다.
    // booleans
    const myFunction = (someBoolean = false) => {
      allow.aBoolean(someBoolean);
      // rest of function...
    }
    
    // functions
    const myFunction = (someCallback = () => {}) => {
      allow.aFunction(someCallback);
      // rest of function...
    }
    
    // React elements
    const myFunction = (someElement = <></>) => {
      allow.aReactElement(someElement);
      // rest of function...
    }
    
    이것들은 그다지 신기한 것이 없다.aBoolean(), aFunction(), aReactElement()이 각각의 데이터 형식을 받지 못하면 모두 실패합니다.

    매거 유형


    받아들일 수 있는 값의 간단한 수조에 따라 매거를 검사할 수 있습니다.또는 대상을 전송할 수 있습니다. 이 경우 대상의 값은 받아들일 수 있는 값을 수집하는 데 사용됩니다.
    // one of...
    const statuses = ['open', 'closed', 'hold'];
    
    const myFunction = (status = '') => {
      allow.oneOf(status, statuses);
      // rest of function...
    }
    
    const colors = {
      red: '#ff0000',
      green: '#00ff00',
      blue: '#0000ff',
    }
    const myFunction = (color = '') => {
      allow.oneOf(color, colors);
      // rest of function...
    }
    
     

    꿰미


    문자열을 검증하는 가장 간단한 방법은 다음과 같습니다.
    // string
    const myFunction = (someString = '') => {
      allow.aString(someString);
      // rest of function...
    }
    
    그러나 함수 논리의 목적에서 빈 문자열은 보통 진정한 유효 문자열이 아니다.또 다른 때는 minLength 또는 maxLength을 지적하고 싶을 수도 있다.따라서 다음과 같이 검증을 사용할 수도 있습니다.
    // strings
    const myFunction = (someString = '') => {
      allow.aString(someString, 1);
      // this ensures that someString is NOT empty
      // rest of function...
    }
    
    const myFunction = (stateAbbreviation = '') => {
      allow.aString(stateAbbreviation, 2, 2);
      // this ensures that stateAbbreviation is EXACTLY 2-characters in 
      // length
      // rest of function...
    }
    
    const myFunction = (description = '') => {
      allow.aString(description, 1, 250);
      // this ensures that description is not empty and is <= 250 
      // characters in length
      // rest of function...
    }
    
     

    숫자


    문자열과 마찬가지로 숫자도 숫자나 비숫자로 간단하게 검증할 수 있다.일정 범위 내에서 검증할 수도 있다.나는 또 내가 allow.aNumber()을 거의 사용하지 않는 것을 발견했지만, 나는 allow.anInteger()을 자주 사용한다.대부분의 경우, 내가 기대하는 것은 숫자이고, 그것들은 사실상 정수이기 때문이다.
    // numbers
    const myFunction = (balance = 0) => {
      allow.aNumber(balance);
      // can be ANY number, positive or negative, integer or decimal
      // rest of function...
    }
    
    const myFunction = (age = 0) => {
      allow.aNumber(age, 0, 125);
      // any number, integer or decimal, >= 0 and <= 125
      // rest of function...
    }
    
    const myFunction = (goalDifferential = 0) => {
      allow.anInteger(goalDifferential);
      // any integer, positive or negative
      // rest of function...
    }
    
    const myFunction = (id = 0) => {
      allow.anInteger(id, 1);
      // any integer, >= 1
      // rest of function...
    }
    
     

    물체


    이것은 특정 유형을 정의하는 데 사용되는 대상이 아닙니다.우리는 anInstanceOf으로 이 점을 설명할 것이다.이것은 단지 어떤 것이 일반적인'대상'의 정의에 부합되는지 검사할 뿐, 만약 당신이 원한다면, 또한 이 대상이 특정한'크기'를 가지고 있는지 검사할 것이다.
    여기에는 null(JavaScript에서 object으로 분류)과 그룹도 포함되지 않습니다.스토리지에 대한 전체 검증은 1분 이내에 확인할 수 있습니다.
    // objects
    const myFunction = (user = {}) => {
      allow.anObject(user);
      // can be ANY object - even an empty object
      // rest of function...
    }
    
    const myFunction = (user = {}) => {
      allow.anObject(user, 1);
      // this doesn't validate the shape of the user object
      // but it ensures that the object isn't empty
      // rest of function...
    }
    
    const myFunction = (user = {}) => {
      allow.anObject(user, 4, 4);
      // again - it doesn't validate the contents of the user object
      // but it ensures that the object has exactly 4 keys
      // rest of function...
    }
    
     

    인스턴스


    이것들은 대상의 형상을 검증했다.모양에서 데이터 유형을 검증하지 않습니다.이러한 인증 수준까지 확장할 수 있습니까?맞다개인 프로그래밍에서 이런 검증 등급이 필요합니까?아니오. 그래서 지금은 키의 존재에만 관심을 갖습니다.
    그것은 또한 검증에 귀속될 것이다.따라서 만약 당신이 하나의 대상을 포함하고 하나의 대상을 포함한다면, 당신은 여전히 anInstanceOf()으로 그것을 검증할 수 있습니다.anInstanceOf()은 개체와 모형 개체를 검사해야 합니다.모델의 모든 키는 필수로 여겨진다.그러나 제공된 객체에는 모델 객체에 없는 다른 키가 있을 수 있습니다.
    // instance of...
    const meModel = {
      name: '',
      address: '',
      degrees: [],
      ancestors: {
        mother: '',
        father: '',
      },
    }
    
    let me = {
      name: 'adam',
      address: '101 Main',
      degrees: [],
      ancestors: {
        mother: 'mary',
        father: 'joe',
      },
      height: '5 foot',
    }
    
    const myFunction = (person = meModel) => {
      allow.anInstanceOf(person, meModel);
      // rest of function...
    }
    myFunction(me);
    // this validates - me has an extra key, but that's ok
    // because me contains all of the keys that exist in 
    // meModel - also notice that meModel is used as the 
    // default value - this provides code-completion clues
    // to your IDE
    
    let me = {
      name: 'adam',
      degrees: [],
      ancestors: {
        mother: 'mary',
        father: 'joe',
      },
      height: '5 foot',
    }
    myFunction(me);
    // this does NOT validate - me is missing the address
    // key that exists in meModel
    
     

    어레이


    가장 간단한 검증은 값이 하나의 그룹이라는 것을 확보하는 것이다.검증을 진행하는 동시에 수조가 비어 있거나 특정한 길이를 가지고 있는지 확인할 수 있습니다.
    // arrays
    const myFunction = (someArray = []) => {
      allow.anArray(someArray);
      // rest of function...
    }
    
    const myFunction = (someArray = []) => {
      allow.anArray(someArray, 1);
      // this ensures that someArray is NOT empty
      // rest of function...
    }
    
    const myFunction = (someArray = []) => {
      allow.anArray(someArray, 2, 2);
      // this ensures that someArray contains EXACTLY 2 elements
      // rest of function...
    }
    
    const myFunction = (someArray = []) => {
      allow.anArray(someArray, 1, 250);
      // this ensures that someArray is not empty and is <= 250 
      // elements in length
      // rest of function...
    }
    
     

    수조


    단지 어떤 것이 하나의 수조라는 것만 알면 통상적으로 부족하다.그룹에 특정한 데이터 형식의 요소가 포함되어 있는지 확인해야 할 수도 있습니다.다시 말하면, 당신은 정수 그룹이나 문자열 그룹 등이 있습니다.
    이 모든 것은 minLength/maxLength의 선택 가능한 매개 변수를 가지고 있기 때문에 수조가 비어 있거나 특정한 크기를 가지고 있는지 확인할 수 있습니다.
    // array of arrays
    const myFunction = (someArray = [[]]) => {
      allow.anArrayOfArrays(someArray);
      // rest of function...
    }
    
    // array of instances
    const myFunction = (someArray = [meModel]) => {
      allow.anArrayOfInstances(someArray, meModel);
      // rest of function...
    }
    
    // array of integers
    const myFunction = (someArray = [0]) => {
      allow.anArrayOfIntegers(someArray);
      // rest of function...
    }
    
    // array of numbers
    const myFunction = (someArray = [0]) => {
      allow.anArrayOfNumbers(someArray);
      // rest of function...
    }
    
    // array of objects
    const myFunction = (someArray = [{}]) => {
      allow.anArrayOfObjects(someArray);
      // rest of function...
    }
    
    // array of strings
    const myFunction = (someArray = ['']) => {
      allow.anArrayOfStrings(someArray);
      // rest of function...
    }
    
     

    실제 세계의 예


    Spotify Toolz 응용 프로그램에서 실행 중인 유형 검사를 사용하고 있습니다.여기서 이 코드를 볼 수 있습니다.
    https://github.com/bytebodger/spotify
    그러나 다음은 내 함수에서 어떤 모습인지 예시입니다.
    const getTrackDescription = (track = trackModel, index = -1) => {
      allow.anInstanceOf(track, trackModel).anInteger(index, is.not.negative);
      return (
         <div key={track.id + index}>
            {index + 1}. {track.name} by {getTrackArtistNames(track)}
         </div>
      );
    }
    
    const comparePlaylists = (playlist1 = playlistModel, playlist2 = playlistModel) => {
      allow.anInstanceOf(playlist1, playlistModel).anInstanceOf(playlist2, playlistModel);
      if (playlist1.name.toLowerCase() < playlist2.name.toLowerCase())
         return -1;
      else if (playlist1.name.toLowerCase() > playlist2.name.toLowerCase())
         return 1;
      else
         return 0;
    };
    
    const addPlaylist = (playlist = playlistModel) => {
      allow.anInstanceOf(playlist, playlistModel);
      local.setItem('playlists', [...playlists, playlist]);
      setPlaylists([...playlists, playlist]);
    }
    
    const addTracks = (playlistId = '', uris = ['']) => {
      allow.aString(playlistId, is.not.empty).anArrayOfStrings(uris, is.not.empty);
      return api.call(the.method.post, `https://api.spotify.com/v1/playlists/${playlistId}/tracks`, {uris});
    }
    
    모든 함수 서명은 한 줄의 코드로 실행될 때 검증됩니다.분명히 이것은 검증을 사용하지 않는 것보다 훨씬 복잡하다.그러나 이것은 혼합물에 TS를 첨가하는 것보다 훨씬 간단하다.
     

    결론


    이것이 TypeScript를 대체합니까?좋아요.아니죠.그러나 나에게 있어서 이 작은 라이브러리는 내가 지난 몇 달 동안 어쩔 수 없이 작성한 절대 다수의 TS 코드보다 더 큰 가치를 제공했다.
    나는 내가 컴파일러와 싸우고 있다는 것을 발견하지 못했다.나는 컴파일러 검사와 실행 시 검사를 작성할 필요가 없다는 것을 발견했다.나는 단지 나의 함수 서명을 검증한 후에 나의 논리와 내용을 쓸 뿐이다. 실행할 때 데이터 형식은 내가 기대하는 것이다.
    아마도 마찬가지로 중요한 것은 나의 IDE가 이 점을 얻었다는 것이다.예를 들어, 객체의 모델을 정의한 다음 함수 서명의 기본값으로 사용할 때 IDE user 객체는 parents 객체를 포함할 수 있으며, 이 객체는 mother 키와 father 키를 포함할 수 있음을 알려줄 필요가 없습니다.
    너는 내가 이곳에서 하는 유형 검사에 경험의 제한이 있다는 것을 알아차릴 수 있을 것이다.예를 들어, 나는 대상의 모양을 검증하고 있지만, 이 대상의 모든 키가 특정 유형의 데이터를 포함하고 있는지 검증하지 않았다.나는 이후에 이 점을 보충할 수 있지만, 나는 이것이 어떤 관건적인 결함이라고 생각하지 않는다.
    봐라, 만약 내가 형상을 전달하고 주어진 대상이 내가 필요로 하는 형상에 부합되는지 검증할 수 있다면, 보통 이 형상의 데이터가 정확한지 걱정할 필요가 없다.통상적으로, 만약 내가 나쁜 물체를 받게 된다면, 물체가 필요한 형상에 부합되지 않는다는 사실을 통해 측정할 수 있다.개체의 모양이 정확하지만 의외의 데이터 형식을 포함하는 경우는 극히 드물다.

    좋은 웹페이지 즐겨찾기