fp-ts:ReaderTaskEither를 사용하여 typescript에서 함수 프로그래밍
만약 우리가 HTTP 요청을 보내고 싶다면이로써 우리는 적어도 다음과 같은 몇 가지를 안다.
Promise
우리는 하나를 처리해야 한다describe
. Reader - 의존항 주입에 사용됩니다.
Task - 비동기적인 사물에 쓰인다.
Either - 실수할 수 있는 일에 대해.
주의:
Reader<A, B>
블록을 포함하는 코드 세그먼트는 Jest 또는 Jasmine로 실행할 수 있습니다.1. 독자
A
는 B
에서 HttpClient
까지의 함수일 뿐이다.그러나 이런 유형의 별명을 가지는 것은 매우 유용하다. 이것은 우리가 의존 주입을 하고 싶다는 것을 의미한다.import * as R from 'fp-ts/lib/Reader'
describe('Reader', () => {
it('should just be a function', () => {
const myReader: R.Reader<number, string> = (a: number) => String(a)
expect(myReader(15)).toBe('15')
})
}
의존 주입을 알면, 클래스 실례를 구조 함수에 주입해서 의존 트리를 만들고, 맨 윗부분 함수에서 파라미터를 보내는 데 익숙해질 수 있습니다. 이 함수는 트리를 두루 돌아다닐 것입니다.이것은 의존항을 먼저 주입한 다음에 함수 파라미터를 전달하는 것을 의미한다.함수식 프로그래밍에서 상황은 정반대이다.외부 의존 함수를 만들기 위해 우선 매개 변수를 주입합니다.오직 이렇게 해야만 우리는 이 의존항을 보내서 파이프를 실행할 수 있다.이 작업이 실제로 어떻게 작동하는지 살펴보겠습니다.유형
Response
과 asks<A, B>(f)
는 가설입니다.// imperative example
class MyController {
private HttpClient client
constructor(HttpClient client) {
this.client = client
}
async fetch(path: string): Response {
return await this.client.get(path)
}
}
// ...
const controller = new MyController(new HttpClient()) // inject dependencies
const res: Response = await controller.fetch('events') // pass parameters and execute
// functional example
import * as R from 'fp-ts/Reader'
// ...
const fetch = (url: string) =>
R.asks((client: HttpClient) => client.get(url))
const fetchEvents = fetch('events') // pass parameters
const res: Response = await fetchEvents(new HttpClient() // inject depdencies and execute
A
는 카드 리더기를 되돌려줍니다. 이 카드 리더기는 f
를 매개 변수로 B
에 제공하고 Task
는 반드시 되돌려야 합니다Promise
.Reader monad에 대한 자세한 내용은 이 문서에서 확인할 수 있습니다.
A note on pipelines
That last example was straightforward, but operations like that involve more logic before and after our
fetch
function. In functional programming we use pipelines to compose functions for more complicated operations. With fp-ts we can use pipe or flow for that. We can rewritefetchEvents
as follows:// with pipe const fetchEvents = pipe('events', fetch) // with flow const fetchEvents = flow(fetch)('events')
With
pipe
andflow
we can easily put more functions in:
- Put them in front of
fetch
for things we want to do to the >events
parameter before calling fetch.- Put them after
fetch
for things we want to do to the result of callingfetch
.
2. 임무
A
Promise
는 ATask
를 되돌려 주는 함수다.이렇게 하면 우리는 우리가 호출할 때까지 집행을 연기할 수 있다. Either
import * as T from 'fp-ts/lib/Task'
describe('Task', () => {
it('of should work', async () => {
// Arrange
const mytask = T.of('abc')
// Act
const result = await mytask()
// Assert
expect(result).toEqual('abc')
})
it('should work with promise', async () => {
// Arrange
const mytask: T.Task<string> = () => Promise.resolve('def')
// Act
const result = await mytask()
// Assert
expect(result).toEqual('def')
})
})
3. 또는
left
는 실패를 예측하는 방법이다.그것은 두 가지 예가 있다.right
와 left
-right
는 고장, Either
는 모든 것이 정상임을 나타낸다.import * as E from 'fp-ts/lib/Either'
describe('Either', () => {
it('of should create a right', () => {
// Act
const myEither = E.of('abc')
// Assert
expect(myEither).toEqual(E.right('abc'))
})
})
fromNullable
일부 조수 구조 함수, 예를 들어 null
매개 변수가 undefined
또는 TaskEither
라면left를 되돌려줍니다.import * as E from 'fp-ts/lib/Either'
describe('Either.fromNullable', () => {
const errorMessage = 'input was null or undefined'
const toEither = E.fromNullable(errorMessage)
it('should return right with string', async () => {
// Arrange
const expected = 'abc'
// Act
const myEither = toEither(expected)
// Assert
expect(myEither).toEqual(E.right(expected))
})
it('should return left with undefined', async () => {
// Act
const myEither = toEither(undefined)
// Assert
expect(myEither).toEqual(E.left(errorMessage))
})
})
4.Task+other=taskother
Either
는 Task
내부tryCatch
로 실패할 수 있는 비동기식 조작임을 의미한다.이것은 우리에게 유용한 함수left
를 제공했다. 두 가지 인자를 받아들인다. 첫 번째는 약속한 함수를 되돌려주는 것이고, 두 번째는 거절당한 결과를 String
에 비추는 함수이다. 이 예에서 우리는 Reader
구조 함수를 사용할 것이다.import * as TE from 'fp-ts/lib/TaskEither'
import * as E from 'fp-ts/lib/Either'
describe('TaskEither', () => {
it('should work with tryCatch with resolved promise', async () => {
// Arrange
const expected = 135345
// Act
const mytask = TE.tryCatch(() => Promise.resolve(expected), String)
const result = await mytask()
// Assert
expect(result).toEqual(E.right(expected))
})
it('should work with tryCatch with rejected promise', async () => {
// Arrange
const expected = 'Dummy error'
// Act
const mytask = TE.tryCatch(() => Promise.reject(expected), String)
const result = await mytask()
// Assert
expect(result).toEqual(E.left(expected))
})
})
Click hereTask,other,taskother에 관한 광범위한 문장을 읽습니다.5. 카드 리더기 + 작업 + 임의 선택 = 카드 리더기 작업
이제 이 부분을 함께 놓고 기능적인 데이터 구조를 만들어서 HTTP 요청을 할 수 있습니다.천진난만한 방법부터 시작하자.
import * as TE from 'fp-ts/lib/TaskEither'
const client = new HttpClient()
const myTryCatch = TE.tryCatch(() => client.get('events'), String)
우리는 currying 을 사용하여 매개 변수화된 클라이언트와 URL을 재구성합니다.const myTryCatch = (url: String) => (client: Client) => TE.tryCatch(() => client.get(url), String)
이 함수의 유형을 설명합니다.type MyTryCatch = (url: string) => (client: HttpClient) => TE.TaskEither<string, Response>
const myTryCatch: MyTryCatch = (url) => (client) => TE.tryCatch(() => client.get(url), String)
현재 우리는 Reader
를 사용하여 형식을 다시 쓸 것이다.type MyTryCatch = (url: string) => Reader<HttpClient, TE.TaskEither<string, Response>>
네가 짐작할 수 있는 바와 같이 aTaskEither
가 aReaderTaskEither
로 돌아오면 aHttpClient
:import * as RTE from 'fp-ts/lib/ReaderTaskEither'
type MyTryCatch = (url: string) => RTE.ReaderTaskEither<HttpClient, string, Response>
이것은 하나의 유형으로 당신이 알아야 할 봉인에 대한 모든 논리를 알려줍니다.string
Response
로 포맷됨Reader
움직이는 거 봤어요.
asks
의 장점은 우리가 ReaderTaskEither
를 사용하여 파이프의 어느 위치에서든 의존 관계를 얻을 수 있다는 점이다. 이 점은 본고에서 이미 논의한 바와 같다.이것이 바로 그것의 작업 원리이다.import * as RTE from 'fp-ts/lib/ReaderTaskEither'
import * as TE from 'fp-ts/lib/TaskEither'
import * as R from 'fp-ts/lib/Reader'
// ...
pipe(
// ...functions leading up to a ReaderTaskEither containing a userId
RTE.chain((userId) =>
R.asks((client: HttpClient) => TE.tryCatch(() => client.get(`user/${userId}`), String))
)
// ...functions handling the response
)
일반적으로 이 함수를 추출하여 파이프를 더 읽을 수 있도록 합니다.pipe(
// ...
RTE.chain(fetchUser)
// ...
)
// ...
const fetchUser = (userId: string) => (client: HttpClient) => TE.tryCatch(() => client.get(`user/${userId}`), String))
If
chain
is unfamiliar to you, it takes a function that maps whatever the monad is holding and returns a monad of something else. In this example it is assumed we start with aReaderTaskEither
of astring
userId and we chain it to aReaderTaskEither
of aResponse
. For more information about monads andchain
in fp-ts checkout
결론
typescript로 함수 프로그래밍을 하는 것은 필수적이지 않기 때문에 하나의 학과이다.비동기적인 동작을 강요하는 것은 없지만, 보상은 함수입니다. 어떤 파이프에서든 사용할 수 있고, 서명을 통해 그 기능을 성실하게 설명할 수 있습니다.그것 또한 매우 좋은 테스트 가능성을 가지고 있다. 사용
Reader
을 통해 우리는 우리가 관심을 가지는 주어진 테스트보다 더 많은 의존성을 필요로 하거나 필요로 하지 않을 수 있는 유형을 실례화할 필요가 없다.자세한 내용은 official documentation를 참조하십시오.
Reference
이 문제에 관하여(fp-ts:ReaderTaskEither를 사용하여 typescript에서 함수 프로그래밍), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/peerhenry/functional-programming-in-typescript-using-fp-ts-readertaskeither-1pei텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)